• std::optional - avoid data copying for RVO

    From David Brown@3:633/10 to All on Fri Apr 24 14:33:50 2026
    I am making some type-safe C++ wrappers for some older C APIs. In one
    case I have a C function that is approximately this (returning 1 if the
    data was successfully copied) :

    extern int try_to_get_data(void *);

    and it is used to get data in a simple struct like :

    struct Data {
    int a;
    float b;
    char c[40];
    };


    A simple and efficient wrapper would then be:

    bool get1(Data& data) {
    return try_to_get_data(&data);
    }

    That does exactly the same thing, but it type-safe.

    However, my preference is that returns from functions are returned,
    rather than passing pointers and references around. The natural
    signature here is thus to return std::optional<Data>. To possible implementations are :

    std::optional<Data> get2() {
    if (Data d; try_to_get_data(&d)) return d;
    return std::nullopt;
    }

    std::optional<Data> get3() {
    std::optional<Data> so;
    if (Data d; try_to_get_data(&d)) so = d;
    return so;
    }

    But these have significant inefficiencies. The local "Data" object
    needs to be created on the stack and its address is passed to the
    external function - then on success, it is copied from the local stack
    object into the caller's stack where the returned std::optional value is
    held. On failure, the whole returned std::optional is cleared - not
    just the "engaged" boolean inside the std::optional implementation.

    I can make my own much-simplified optional type with additional
    accessors to get the address of the payload field and to allow directly changing the "engaged" field without affecting the payload. Then I can
    have :

    Simple get5() {
    Simple so;
    so.set_engaged(try_to_get_data(&so.value()));
    return so;
    }

    This gives me optimal generated code.

    Is there anything I am missing from std::optional that would let me have
    this kind of direct access? I suspect not, since that kind of access
    bypasses the safety of std::optional of only having access to the
    payload if it is engaged. But avoiding the copying makes a big
    difference to the efficiency for large optionals.

    And is there a good reason for clearing out the payload here when
    returning nullopt? Or is that just an inefficiency of the gcc standard
    C++ library implementation?


    --- PyGate Linux v1.5.14
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)