Using Storage Pointers Instead of Memory (with caution)

Published by Mario Oettler on

Last Updated on 24. March 2025 by Mario Oettler

So far, we have learned that storage is expensive and memory is relatively cheap. But there are cases where storage, or rather storage pointers, are the more gas-efficient choice.

The following code uses a storage pointer.

pragma solidity 0.8.29;

contract StoragePointer_StoragePointer{
    struct Vehicle{
        uint256 varA;
        uint256 varB;
    }

    mapping(uint256 => Vehicle) public vehicles;

    constructor(){
        vehicles[0] = Vehicle(1,2);
    }

    function returnValue() public returns(uint256){
        Vehicle storage myVehicle = vehicles[0];
        uint256 varC = myVehicle.varA + 5;
        return varC;
    }
}

The following code uses memory.

pragma solidity 0.8.29;

contract StoragePointer_StoragePointer{
    struct Vehicle{
        uint256 varA;
        uint256 varB;
    }

    mapping(uint256 => Vehicle) public vehicles;

    constructor(){
        vehicles[0] = Vehicle(1,2);
    }

    function returnValue() public returns(uint256){
        Vehicle storage myVehicle = vehicles[0];
        uint256 varC = myVehicle.varA + 5;
        return varC;
    }
}

The gas costs are:

 setValues()
Storage Pointer27330
Memory29831

However, this solution has a significant drawback. When writing to a storage pointer, the underlying storage is changed. When using the memory version, it would simply change the value in memory.

pragma solidity 0.8.29;

contract StoragePointer01{
    struct Vehicle{
        uint256 varA;
        uint256 varB;
    }

    mapping(uint256 => Vehicle) public vehicles;

    constructor(){
        vehicles[0] = Vehicle(1,2);
    }

    function changeValue() public{
        Vehicle storage myVehicle = vehicles[0];
        myVehicle.varA = 123;
    }
}

This can be an unexpected behaviour, especially for less experienced developers, if they don’t see that the line of code

Vehicle storage myVehicle = vehicles[0]

creates a storage pointer rather than a copy. If you change the value of varA (or varB) in myVehicle, the change is not made in a separate variable. Instead, the value of vehicles[0].varA is changed.

Categories: