Suppose I have the following:
#include <memory>
struct A { int x; };
class B {
B(int x, std::unique_ptr<A> a);
};
class C : public B {
C(std::unique_ptr<A> a) : B(a->x, std::move(a)) {}
};
If I understand the C++ rules about "unspecified order of function parameters" correctly, this code is unsafe. If the second argument to B
's constructor is constructed first using the move constructor, then a
now contains a nullptr
and the expression a->x
will trigger undefined behavior (likely segfault). If the first argument is constructed first, then everything will work as intended.
If this were a normal function call, we could just create a temporary:
auto x = a->x
B b{x, std::move(a)};
But in the class initialization list we don't have the freedom to create temporary variables.
Suppose I cannot change B
, is there any possible way to accomplish the above? Namely dereferencing and moving a unique_ptr
in the same function call expression without creating a temporary?
What if you could change B
's constructor but not add new methods such as setX(int)
? Would that help?
Thank you
B
's constructor you don't need to do any of this. Just have a single argument,unique_ptr<A>
and do the copy ofa->x
in the constructor's initialization list. – KeitloaB
's interface in such a way to support this specific usage. Initializingx
witha->x
might not be a expected thing to do and thus should not require a special case fromB
. It depends on the context, but it might be more natural for a constructor taking only theunique_ptr
to initializex
to some default constant instead ofa->x
. If we changeB
to take theunique_ptr
by rvalue reference, we give callers more flexibility for free and don't change the interface. I don't see any reason why theunique_ptr
argument should be passed by value here. – BatchB
constructor, and adding an overload that takes only aunique_ptr<A>
. In that case it's impliedB
will initializex
froma->x
. Which one you choose really depends on the intended use of your class. – Keitloa