In C++, we can assign an object to a non-const reference. So this works:
Foo &foo = Foo();
But, C++ doesn't allow a temporary to be assigned to a non-const reference. So this is not allowed:
Bar::Bar(Foo &foo = Foo()) {}
But this is allowed
Bar::Bar(const Foo &foo = Foo()) {}
I have three questions here:
What is the scope of foo in the last case? Does it live even after the constructor is exited. From what I read, the lifetime of a temporary is modified if it is assigned to a const reference, in which case it takes up the lifetime of the reference is it assigned to. What is the lifetime of the default argument, in this case foo?
I tried the second example in MSVC and it didn't complain. I also noticed that the lifetime of the temporary was still extended. So I could use foo after the constructor exited. What is that about?
My scenario demands the default argument to constructor in this manner and I will need to modify the argument in the constructor (so I cannot make it const). And I also need to use foo after the constructor has exited. What is the best design to cater to this scenario?
Thanks in advance.
What is the scope of foo in the last case?
foo is a constructor (same applies to regular functions too) argument, so its lifetime ends when the full expression containing the call to the constructor ends. Thanks aschepler!
What is the lifetime of the default argument, in this case foo?
You extended the lifetime of the default argument by binding it to Foo const& foo, so its lifetime will match that of the reference it's bound to, i.e. until the constructor body exits.
I tried the second example in MSVC and it didn't complain.
It does if you set the warning level to /W4; in that case it'll warn you about a non-standard extension being used. AFAIK, the semantics are the same as the previous case.
My scenario demands the default argument to constructor in this manner and I will need to modify the argument in the constructor (so I cannot make it const). And I also need to use foo after the constructor has exited.
It depends on whether you want to save it as member of Bar or not. If it's the former, use an rvalue reference and move the argument
Bar::Bar(Foo&& foo = Foo()) : f_(std::move(foo)) {} // f_ is a member of type Foo
Otherwise, just leave out the default argument. You can also create both overloads to cover different situations.
foo and its temporary are gone after the constructor completes.
It's a MS extension that doesn't follow the language standard.
Don't use temporary default values in this case. If you need to be able to access it after the constructor completes, you need to create the object yourself prior to calling the constructor, and pass that in by reference.
My scenario demands the default argument to constructor in this manner
and I will need to modify the argument in the constructor (so I cannot
make it const). And I also need to use foo after the constructor has
exited. What is the best design to cater to this scenario?
You could make an optional<Foo> inside Bar, as in:
struct Bar
{
Bar() : optionalFoo(boost::in_place()), foo(*optionalFoo) {}
Bar(Foo& f) : foo(f) {}
Bar(Bar const&) = delete; // Compiler generated one is incorrect
private:
boost::optional<Foo> optionalFoo;
Foo& foo;
};
But classes that optionally own their data get tricky, especially when it comes to copying/moving.
In this case (as in most cases), the lifetime of a temporary bound directly to a reference is extended to the lifetime of the reference. So the temporary will be valid as long as foo is, i.e. for the duration of the constructor. It will end when the full-expression containing the constructor call ends.
MSVC has an extension which allows temporaries to bind to non-const references. It's not standard and other compilers don't support it. Don't use this unless you are (and always will be) coding for MSVC only.
That depends on what you actually want to achieve - there's not enough information in your question to answer that. If you need it to persist even after the constructor exits, you need to provide an actual object with appropriate lifetime. You could provide a per-thread static member, for example:
class Bar
{
static thread_local Foo ctor_default_foo;
public:
Bar(Foo &foo = ctor_default_foo) {}
};
Note that this of course means that all objects created by one thread using the default argument would share the same Foo object. If you need a new one for each Bar object, you'll have to change your design. But to tell you how, we'd need to know more about the actual use case.
Related
We have Myclass &funcref(); and Myclass func(); and assign the return value to a variable (not a variable reference). If I understand correctly we use the copy constructor in both cases. The only difference is that funcref() returns a reference, and we copy over what is refers to into our object, while in func(), we copy the object while returning.
If we assign it to a variable reference, only func() still needs a copy constructor.
I hope everything until now is correct - if not, please point out my missunderstanding.
Now my question:
It seems like whether we assign the return value of func() to a variable, or a variable reference, it does not change anything at all? Is there any case in which those two will differ? At least when they are assigned, it seems like the process is the same, but I may be wrong.
In code:
class My_class {
//Anything may be here
};
My_class func();
My_class &funcref();
int main() {
My_class a = func(); //Copy operator used?
const My_class &b = func(); //Why does this need to be constant? Also, this uses copy operator, right?
My_class c = funcref(); //Copy operator used?
My_class &d = funcref(); //Here, we do not need a copy operator, right?
}
Main question: Except for b being const, is there any difference between a and b? Both seem to be on the stack of main, so do they differ in any way?
If I understand correctly we use the copy constructor in both cases.
Not quite. In C++11, move constructor will be used in case of Myclass func() (and compiler is allowed to optimise the copy / move away).
Since C++17, there is neither move nor copy in case of Myclass func().
Is there any case in which those two will differ?
It is somewhat unclear what cases you are asking about. There is a differenceiIn the case where the function returns a reference.
if I am calling any function that returns a non-reference, should I assign the output as a reference, or not as a reference?
Typically, you should use an object variable because that is simpler and doesn't involve the cognitive load of having to understand reference bound temporary lifetime extension rules.
Only case I can think of where reference variable for prvalue makes sense is a template context where the called function might return a reference, or a non-reference object that acts as a reference wrapper. I believe that case is the reason why temporary lifetime extension exists.
I am referencing this SO answer Does D have something akin to C++0x's move semantics?
Next, you can override C++'s constructor(constructor &&that) by defining this(Struct that). Likewise, you can override the assign with opAssign(Struct that). In both cases, you need to make sure that you destroy the values of that.
He gives an example like this:
// Move operations
this(UniquePtr!T that) {
this.ptr = that.ptr;
that.ptr = null;
}
Will the variable that always get moved? Or could it happen that the variable that could get copied in some situations?
It would be unfortunate if I would only null the ptr on a temporary copy.
Well, you can also take a look at this SO question:
Questions about postblit and move semantics
The way that a struct is copied in D is that its memory is blitted, and then if it has a postblit constructor, its postblit constructor is called. And if the compiler determines that a copy isn't actually necessary, then it will just not call the postblit constructor and will not call the destructor on the original object. So, it will have moved the object rather than copy it.
In particular, according to TDPL (p.251), the language guarantees that
All anonymous rvalues are moved, not copied. A call to this(this)
is never inserted when the source is an anonymous rvalue (i.e., a
temporary as featured in the function hun above).
All named temporaries that are stack-allocated inside a function and
then returned elide a call to this(this).
There is no guarantee that other potential elisions are observed.
So, in other cases, the compiler may or may not elide copies, depending on the current compiler implementation and optimization level (e.g. if you pass an lvalue to a function that takes it by value, and that variable is never referenced again after the function call).
So, if you have
void foo(Bar bar)
{}
then whether the argument to foo gets moved or not depends on whether it was an rvalue or an lvalue. If it's an rvalue, it will be moved, whereas if it's an lvalue, it probably won't be (but might depending on the calling code and the compiler).
So, if you have
void foo(UniquePtr!T ptr)
{}
ptr will be moved if foo was passed an rvalue and may or may not be moved it it's passed an lvalue (though generally not). So, what happens with the internals of UniquePtr depends on how you implemented it. If UniquePtr disabled the postblit constructor so that it can't be copied, then passing an rvalue will move the argument, and passing an lvalue will result in a compilation error (since the rvalue is guaranteed to be moved, whereas the lvalue is not).
Now, what you have is
this(UniquePtr!T that)
{
this.ptr = that.ptr;
that.ptr = null;
}
which appears to act like the current type has the same members as those of its argument. So, I assume that what you're actually trying to do here is a copy constructor / move constructor for UniquePtr and not a constructor for an arbitrary type that takes a UniquePtr!T. And if that's what you're doing, then you'd want a postblit constructor - this(this) - and not one that takes the same type as the struct itself (since D does not have copy constructors). So, if what you want is a copy constructor, then you do something like
this(this)
{
// Do any deep copying you want here. e.g.
arr = arr.dup;
}
But if a bitwise copy of your struct's elements works for your type, then you don't need a postblit constructor. But moving is built-in, so you don't need to declare a move constructor regardless (a move will just blit the struct's members). Rather, if what you want is to guarantee that the object is moved and never copied, then what you want to do is disable the struct's postblit constructor. e.g.
#disable this(this);
Then any and all times that you pass a UniquePtr!T anywhere, it's guaranteed to be a move or a compilation error. And while I would have thought that you might have to disable opAssign separately to disable assignment, from the looks of it (based on the code that I just tested), you don't even have to disable assignment separately. Disabling the postblit constructor also disables the assignment operator. But if that weren't the case, then you'd just have to disable opOpAssign as well.
JMD answer covers theoretical part of move semantics, I can extend it with a very simplified example implementation:
struct UniquePtr(T)
{
private T* ptr;
#disable this(this);
UniquePtr release()
{
scope(exit) this.ptr = null;
return UniquePtr(this.ptr);
}
}
// some function that takes argument by value:
void foo ( UniquePtr!int ) { }
auto p = UniquePtr!int(new int);
// won't compile, postblit constructor is disabled
foo(p);
// ok, release() returns a new rvalue which is
// guaranteed to be moved without copying
foo(p.release());
// release also resets previous pointer:
assert(p.ptr is null);
I think I can answer it myself. Quoting the "The Programming Language":
All anonymous rvalues are moved, not copied. A call to this ( this ) is never inserted
when the source is an anonymous rvalue (i.e., a temporary as featured in
the function hun above).
If I understood it correctly, this means that this(Struct that) will never be a copy, because it only accepts rvalues in the first place.
Simple example:
struct A
{
A() : i(int()) {}
const int& i;
};
Error from gcc:
a temporary bound to 'A::i' only persists until the constructor exits
Rule from 12.2p5:
A temporary bound to a reference member in a constructor’s
ctor-initializer (12.6.2) persists until the constructor exits.
Question
Does anybody know the rationale for this rule? It would seem to me that allowing the temporary to live until reference dies would be better.
I don't think the not extending to the object lifetime needs justification. The opposite would!
The lifetime extension of a temporary extends merely to the enclosing scope, which is both natural and useful. This is because we have tight control on the lifetime of the receiving reference variable. By contrast, the class member isn't really "in scope" at all. Imagine this:
int foo();
struct Bar
{
Bar(int const &, int const &, int const &) : /* bind */ { }
int & a, & b, & c;
};
Bar * p = new Bar(foo(), foo(), foo());
It'd be nigh impossible to define a meaningful lifetime extension for the foo() temporaries.
Instead, we have the default behaviour that the lifetime of the foo() temporary extends to the end of the full-expression in which it is contained, and no further.
The int() in your constructor initialization list is on the stack.
Once that value is set, int() goes out of the scope and the reference becomes invalid.
What memory would it live in?
For it to work the way you propose, it can't be on the stack since it has to live longer than any single function call. It can't be put after struct A in memory, because it would have no way to know how A was allocated.
At best, it would have to be turned into a secret heap allocation. That would then require a corresponding secret deallocation when the destructor runs. The copy constructor and assignment operator would need secret behavior too.
I don't know if anyone ever actually considered such a way of doing it. But personally, it sounds like too much extra complexity for a rather obscure feature.
is it possible to restrict class instances to be used only as rvalues (e.g. temporaries)?
for example, I have class Wrapper whose constructor takes A const& and saves this reference in its member. It's a dangerous because lifetime of Wrapper instance cannot be longer than lifetime of A instance, but it's fine if Wrapper is temporary.
I think that even wanting to do this is a sign of a really bad design.
However, you could make all constructors private and make a friend function that returns an rvalue. That should do the trick.
I don't think it would be safe:
const A &a = YourClass( tmp );
YourClass in this case is the class you're looking for which only allow temporary instances, tmp is the temporary value you pass to the constructor.
It's possible (ie: safe, defined behavior) to have a constant reference to a temporary (ie: a), but the temporary itself (such instance of YourClass) has got a reference to tmp which is no longer valid after that expression is evaluated.
Not exactly the answer you are looking for, but have you thought about weak pointers? (for example, boost::weak_ptr). In this case, the original A would be held in a shared_ptr and the Wrapper constructor accepts a weak_ptr. The neat thing with this approach is that, before each usage of the weak_ptr, you can attempt to lock() which will give you a shared_ptr - if that fails, you know that A is gone and Wrapper cannot function... But it's handled cleanly...
This might do the job unless your class has public data members.
Basically, the idea is not to restrict the construction of the wrapper but to make sure that instances can be used (just like you said) only as long as they are temporary values. One can achieve this by overloading all methods and deleting (or making them private) those that refer to const&.
Here's a simple example:
class Wrapper
{
public:
Wrapper() = default;
Wrapper(const std::string& name) : name(name) {}
void process() && { std::cout << "Greetings from " << name << std::endl; }
// Only temporary instances of this class are allowed!
void process() const & = delete;
private:
std::string name;
};
And some use cases:
Wrapper("John").process(); // intended use case
Wrapper j; // create whatever you want
j.process(); // error C2280: 'void Wrapper::process(void) const &': attempting to reference a deleted function
std::move(j).process(); // this is still possible
const Wrapper& t = Wrapper(); // bind the temporary to a const reference - not a problem because ...
t.process(); // error C2280: 'void Wrapper::process(void) const &': attempting to reference a deleted function
The obvious disadvantages are:
You have to overload every public member function.
The error message is delayed and not very informative.
A similar thing has been done in the standard. The make routines for std::reference_wrapper do not accept temporaries.
Note that they considered another subtlety: the overload uses const T&& instead of T&&. This can be important in our case as well. For example, if your wrapper is deliberately designed to be noncopyable and you use make routines such as
const Wrapper make_wrapper();
instead of
Wrapper make_wrapper();
In this case, you might want to replace
void process() &&;
by
void process() const &&;
I'd not bother enforcing this at compile time, as there are always going to be corner cases where this would be overly restrictive, limiting the usefulness of the class, but rather wrap tools like valgrind or Purify so I can spot places where invalidated references are used.
I believe in C++17 and later you can get approximately what you want by doing the following:
Delete the move constructor for your type (and don't define a copy constructor).
Always accept your type by value in APIs.
So, for example:
#include <type_traits>
#include <utility>
// A non-moveable, non-copyable type.
struct CantMove {
CantMove(CantMove&&) = delete;
CantMove(int) {} // Some other constructor
};
static_assert(!std::is_move_constructible_v<CantMove>);
static_assert(!std::is_copy_constructible_v<CantMove>);
// A function that accepts it by value.
bool AcceptByValue(CantMove input) { return true; }
// It's possible to call the value-accepting API when the input is a prvalue
// (which in previous versions of C++ would have been a temporary).
bool unused = AcceptByValue(CantMove(0));
// But it's not possible to call with a named value, even when casted to an
// rvalue reference. This doesn't compile.
CantMove cant_move(0);
bool unused_2 = AcceptByValue(std::move(cant_move));
It's possible to provide the value-accepting function with what we previously called a temporary because guaranteed copy elision says that there isn't even a temporary involved anymore—the only CantMove object created is the function parameter itself, so there is no move- or copy-construction involved. In contrast it's not possible to call with std::move(cant_move) because that would involve move-constructing the function parameter, and the type is not move-constructible.
Of course it's still possible to initialize a CantMove directly:
CantMove foo{0};
But if you own all of the APIs that accept a CantMove and make them all accept by value, then you can't actually do anything with foo afterward. This means it would be hard for a user to do this by mistake and not realize the problem.
Yes, you could.
You would make the constructor and regular copy-constructor/assign private but make the r-value move semantics (C++0x) public.
You would have a static or friend constructor to create the temporary.
In 2003 C++ you would also be able to use this to bind to a const reference.
Of course you'd have the issue that your const reference would probably become invalidated after the statement.
I am really confused now on how and which method to use to return object from a function. I want some feedback on the solutions for the given requirements.
Scenario A:
The returned object is to be stored in a variable which need not be modified during its lifetime. Thus,
const Foo SomeClass::GetFoo() {
return Foo();
}
invoked as:
someMethod() {
const Foo& l_Foo = someClassPInstance->GetFoo();
//...
}
Scneraio B:
The returned object is to be stored in a variable which will be modified during its lifetime. Thus,
void SomeClass::GetFoo(Foo& a_Foo_ref) {
a_Foo_ref = Foo();
}
invoked as:
someMethod() {
Foo l_Foo;
someClassPInstance->GetFoo(l_Foo);
//...
}
I have one question here: Lets say that Foo cannot have a default constructor. Then how would you deal with that in this situation, since we cant write this anymore:
Foo l_Foo
Scenario C:
Foo SomeClass::GetFoo() {
return Foo();
}
invoked as:
someMethod() {
Foo l_Foo = someClassPInstance->GetFoo();
//...
}
I think this is not the recommended approach since it would incur constructing extra temporaries.
What do you think ? Also, do you recommend a better way to handle this instead ?
First, let's look into the things that come into play here:
(a) Extending lifetime of a temporary when it's used to initialize a reference - I learnt about it in this publication by Andrei Anexandrescu. Again, it feels weird but useful:
class Foo { ... }
Foo GetFoo() { return Foo(); } // returning temporary
void UseGetFoo()
{
Foo const & foo = GetFoo();
// ... rock'n'roll ...
foo.StillHere();
}
The rule says that when a reference is initialized with a temporary, the temporary's lifetime is extended until the reference goes out of scope. (this reply quotes the canon)
(b) Return Value Optimization - (wikipedia) - the two copies local --> return value --> local may be omitted under circumstances. That's a surprising rule, as it allows the compiler to change the observable behavior, but useful.
There you have it. C++ - weird but useful.
So looking at your scenarios
Scenario A: you are returning a temporary, and bind it to a reference - the temporary's lifetime is extended to the lifetime of l_Foo.
Note that this wouldn't work if GetFoo would return a reference rather than a temporary.
Scenario B: Works, except that it forces a Construct-Construct-Copy-Cycle (which may be much more expensive than single construct), and the problem you mention about requiring a default constructor.
I wouldn't use that pattern to create a object - only to mutate an existing one.
Scenario C: The copies of temporaries can be omitted by the compiler (as of RVO rule). There is unfortunately no guarantee - but modern compilers do implement RVO.
Rvalue references in C++ 0x allows Foo to implement a resource pilfering constructor that not only guarantees supression of the copies, but comes in handy in other scenarios as well.
(I doubt that there's a compiler that implements rvalue references but not RVO. However there are scenarios where RVO can't kick in.)
A question like this requires mentioning smart pointers, such as shared_ptr and unique_ptr (the latter being a "safe" auto_ptr). They are also in C++ 0x. They provide an alternate pattern for functions creating objects.
Out of the three scenarios, number 3 is the ideomatic method, and the one you should probably use. You won't be paying for extra copies because the compiler is free to use copy elision to avoid the copy if possible.
Secnario A is wrong. You end up with a reference to a temporary which is destroyed when the statement containing the function call finishes. Okay, Scenario A is not wrong, but you should still use Scenario C.
Secnario B works just fine, but:
Lets say that Foo cannot have a default constructor. Then how would you deal with that in this situation, since we cant write this anymore: Foo l_Foo.
Foo has to have a default constructor. Even if you don't give it one, the compiler must for you. Assuming you declare a private constructor, there's no way you can use this calling method. You need to either make Foo default constructable or use Secnario C.