Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if return value is consumed

Tags:

c++

c++17

Given a function which returns a heavy-to-construct and heavy-to-destroy object, is there a way to skip object construction and destruction if the function return value is not consumed?

HeavyObject func();
auto res = func(); // heavy object is constructed and returned
func(); // lightweight "null" object is returned and immediately destroyed

Is there a technique which I can use except tag dispatching like void func(NotConsumed);?

Update

It is okay to discard the return value, so [[nodiscard]] is not an option. Clients can decide if they want to use the result or not.

Let's assume func() initiates some job and HeavyObject serves as a some sort of handle. Clients can use it later to control/monitor the job, if they want to. Construction of such handle could involve e.g. creating pipes or heap memory allocation.

There are other overloads of func() where the return value must be consumed and which are marked as [[nodiscard]]. The new overload does not have this requirement but must be compatible with existing API.

like image 271
Kane Avatar asked Mar 10 '26 12:03

Kane


1 Answers

Since C++17 there is the nodiscard attribute. However, this will only help to not ignore the returned value and the compiler is only encouraged to issue a warning.

I don't think there is a simple answer for what you want (ie no second function or overload). Also because the construction of the heavy object takes place already inside the function, not after it returned.

What you can do is to return a proxy that only when needed constructs the heavy object. Something along the line of :

struct heavy_object { int x; };

struct proxy {
    int parameter_needed_to_construct_heavy_object;
    operator heavy_object() {
        return {parameter_needed_to_construct_heavy_object};
    }
};

proxy func() {
    return {42};
}

int main() {
    func(); // ok, no heavy object is constructed
    heavy_object ho = func(); // ok, heavy object is constructed
    auto x = func(); // "ok-ish", caller must be aware that x is just the proxy
}

Instead of an implicit converions a get() could take its place, but that wont change the fact that the caller must do something extra to get the actual return value.

Having said that, I think using two seperate functions or an overload as you propse is the simpler and cleaner solution.

like image 148
463035818_is_not_a_number Avatar answered Mar 12 '26 01:03

463035818_is_not_a_number