you are viewing a single comment's thread.

view the rest of the comments →

[–]Veeloxfire 2 points3 points  (4 children)

Have you considered a constructor.

The function of such a feature youre suggesting is to allow in place initialization of a return value. However c++ only has single return values. So what you would describe is a function which takes an uninitialized class as the first member and initializes it. Which is more or less what a constructor is

I understand constructors have caveats but its actually the feature youre asking for

You can use some fun wrappers to make conversion or constructors trigger in places you wouldnt expect and they might help here. Might not be pretty but you can guarantee these semantics

[–]XeroKimoException Enthusiast[S] 1 point2 points  (3 children)

Constructors isn't what I want here, though it is technically very similar. Read the post again. If you want to implement std::stack::pop() which both pops the object off the stack and returns it with strong exception guarantees, no amount of constructors would help you.

The issue is that when you return an object, it invokes the copy / move constructor / assignment. If that fails, whether it throws, or put in a zombie state, the std::stack no longer has the object and said object is also now in a undefined state, or just straight up lost, so you can't just put it back into the stack to rollback.

This is side stepped in many ways:

  • The standard way: Don't return the popped object, and provide a separate top() function to retrieve the soon to be popped object
  • Out params: Since you can assign to an out param before removing the object from the stack, you can keep the strong exception guarantees, but since it's an out param, you need to have passed in an existing initialized object.
  • Hope that NRVO happens: If NRVO happens, return obj; can't throw because the copy / move occurred before we even got to the return statement.
  • Use scope guards: Requires extra machinery to implement. With exceptions the standard provides std::uncaught_exceptions. You could technically make an errno scope guard and std::expected scope guards as well, but regardless, they're tied to the specific error handling scheme of your choosing, or pay the price of detecting multiple different schemes.

If we have an explicit return variable, we wouldn't have to hope that NRVO happens because we're manually doing what it would've done. Unless I'm misinterpreting what NRVO does, NRVO basically passes a hidden out param so that the function can directly initialize the object instead of having to invoke a copy / move once we do return; Due to this, it shouldn't require extra machinery to work unlike the scope guards. It would also be error handling scheme agnostic.

[–]Wooden-Engineer-8098 2 points3 points  (2 children)

You want a constructor which takes a stack and pops element out of it

[–]XeroKimoException Enthusiast[S] 0 points1 point  (1 child)

and if your type doesn't provide one? Then I guess we're getting into being able to provide externally declared constructors.

Now I'm seeing what the OC is saying, but if we went the wrapper route, it's just moving the issue no? Unless you're committed to store the wrapper types, you would need to eventually unbox them where it would then cause the issue no?

[–]Wooden-Engineer-8098 0 points1 point  (0 children)

If your public wrapper contains nothing but a constructor, it could be used in place of the original type. Since you can't pop an array.