Are moved-from objects required to be destructed? - c++

If I move-construct a from b, is it still necessary to destruct b, or can I get away without doing so?
This question crossed my mind during the implementation of an optional<T> template. Excerpt:
~optional()
{
if (initialized)
{
reinterpret_cast<T*>(data)->~T();
}
}
optional(optional&& o) : initialized(o.initialized)
{
if (initialized)
{
new(data) T(std::move(*o)); // move from o.data
o.initialized = false; // o.data won't be destructed anymore!
}
}
Of course, I could just replace the bool initialized with a three-valued enumeration that distinguishes between initialized, non-initialized and moved-from. I just want to know if this is strictly necessary.

Yes, it is still necessary to destruct b. A moved from object is a valid, constructed object. In some cases, it may even hold resources that still need to be disposed of. In generic code such as you show, T may not even have a move constructor. You may invoke a copy constructor instead in this case. So you can definitely not assume that ~T() is a no-op and can be elided.

Yes, you do still have to destruct them. One of the designs that can show this flaw is for example, observer-based patterns where one object keeps lists of pointers to another. Not running the destructor won't remove the pointer and the code will crash when it attempts to access an object that no longer exists.
The easier thing to do in your example is just to not set initialized to false in the moved-from object. The value is still defined to be in a valid state after being moved from, and the destructor of the rvalue you're referring to would clean it up with no further intervention.

I'd like to answer 'No' to your question but I'm not sure it's even the right question to ask. Consider the following:
{ // start of scope
T maybe_moved;
if(some_condition) {
T(std::move(maybe_moved));
}
// end of scope
}
T::~T() should obviously be called only once for the maybe_moved object. If a move constructor would call it, how would you make such innocuous code work?

Related

Requirements on returned type that may have some member functions SFINAE'd away in the function's translation unit?

Refining from Why is the destructor implicitly called?
My understanding of calling convention is that functions construct their result where the caller asked them to (or in a conventional place?). With that in mind, this surprises me:
#include <memory>
struct X; // Incomplete type.
// Placement-new a null unique_ptr in-place:
void constructAt(std::unique_ptr<X>* ptr) { new (&ptr) std::unique_ptr<X>{nullptr}; }
// Return a null unique_ptr:
std::unique_ptr<X> foo() { return std::unique_ptr<X>{nullptr}; }
https://godbolt.org/z/rqb1fKq3x
Whereas constructAt compiles, happily placement-newing a null unique_ptr<X>, foo() doesn't compile because the compiler wants to instantiate unique_ptr<X>::~unique_ptr(). I understand why it can't instantiate that destructor (because as far as the language is concerned, it needs to follow the non-nullptr branch of the d'tor that then deletes the memory [https://stackoverflow.com/questions/28521950/why-does-unique-ptrtunique-ptr-need-the-definition-of-t]). Basically without a complete X, the unique_ptr's destructor is SFINAE'd away (right?). But why does a function returning a value have to know how to destruct that value? Isn't the caller the one that will have to destruct it?
Clearly my constructAt and foo functions aren't morally equivalent. Is this language pedantry, or is there some code path (exceptions?) where foo() would have to destruct that value?
In your specific case there is no way that the destructor may be invoked. However, the standard specifies the situations in which the destructor is potentially invoked in more general terms. If a destructor is potentially invoked it requires a definition (even if there is no path that could call it) and this will therefore cause implicit instantiation which fails in your case since instantiation of the std::unique_ptr<X> destructor requires X to be complete.
In particular the destructor is potentially invoked for every result object in a return statement.
I think the reason for this choice is described in CWG issue 2176: In general there may be local variables and temporaries in the function which are destroyed after the result object of the return statement has been constructed. But if the destruction of one of these objects throws an exception, then the already constructed result object should also be destroyed. This requires the destructor to be defined.
CWG issue 2426 then made the destructor potentially invoked even if there is no actual invocation due to the above reasoning, in line with implementations. I assume this choice was made simply because it doesn't require any additional decision making on the compiler's part and was already implemented.

Returning rvalue reference

I'm trying to get my head around this code that I'm looking at:
class ShipFactory
{
public:
Ship make_ship(....) { ... }
static std::unique_ptr<ShipFactory>&& get_factory()
{
if (!m_factory) {
m_factory.reset(new ShipFactory);
}
return std::move(m_factory);
}
...
public:
static std::unique_ptr<ShipFactory> m_factory;
};
std::unique_ptr<ShipFactory> ShipFactory::m_factory;
...
// used like this:
ship = ShipFactory::get_factory()->make_ship(...);
My question is about the get_factory method. I don't really understand why it's returning an rvalue reference to a std::unique_ptr or what that will do. I'm also not entirely convinced it's valid.
Unlike auto_ptr, you can't copy a unique_ptr since that constructor is deleted and that would make no sense for the unique_ptr since it owns the memory it points to, but you can move it. This is what's happening here, resets a unique_ptr, and moves it. It has the same effect as:
auto ship = make_unique<ShipFactory>();
Remember that std::move doesn’t move anything; it merely allows a move to happen (and causes rvalue references that (presumably) move to be preferred in overload resolution).
Returning an rvalue reference (to something that is not destroyed when leaving the function!) is an offer of the object’s resources to the client:
auto s=ShipFactory::get_factory()->make_ship(…); // use the current factory
auto f=ShipFactory::get_factory(); // take the whole current factory
Both lines create a factory if there is no current factory; the second causes there to be no current factory thereafter (but the unique_ptr f can still be used).

Construct returned object in calling function's scope

Is it possible to force C++ to construct an object in the scope of a calling function? What I mean is to explicitly do what an return value optimization (RVO) does.
I have some container classes which are in a chain of derivation. Since the classes are constructed with stack data, they can't be returned, so I disabled the copy constructor and assignment operators. For each class, I am providing an iterator. The constructor of each iterator has only one argument: a pointer to the container class. To get the iterator, I want to use this function:
BindPackIterator BindPack.begin(void)
{
return BindPackIterator(this);
}
in this context:
for (auto i=bindpack.begin(); !i.end(); ++i) { i.run(); }
The compiler issues errors, complaining about not being able to copy the BindPackIterator object. Remember, I disabled them.
What I want to happen is for the BindPackIterator to be instantiated in the calling function's scope to avoid either a copy or move operation.
In this particular case, I know I can do a workaround, changing the begin function to return a BindPack pointer,
for(BindPackIterator i=bindpack.begin(); !i.end(); ++i) { i.run(); }
and I've experimented a bit, without success, with decltype and this construction:
auto BindPack::begin(void) -> BindPackIterator
{
return BindPackIterator(this);
}
This is just the example with which I'm currently frustrated. There have been other projects where the obvious solution is for the function to instantiate an object in the calling function's scope. The move constructor (foo&&) helps in some cases, but for objects with many data members, even that can be inefficient. Is there a design pattern that allows object construction/instantiation in the caller's scope?
Putting n.m.'s comment into code, write a constructor for BindPackIterator that takes a BindPack and initializes the iterator in the "begin" state. e.g:
BindPackIterator(BindPack* pack) : pack(pack), pos(0){ }
That you can use in your for loop:
BindPack pack;
for(BindPackIterator i(&pack); !i.end(); ++i){
i.run();
}
Live demo
Is it fair to say that the answer is "No," it is not possible to construct a returned object in the calling function's scope? Or in other words, you can't explicitly tell the compiler to use RVO.
To be sure, it is a dangerous possibility: stack memory used to construct the object while available in the called function will not be valid in the calling function, even though the values might remain untouched in the abandoned stack frame. This would result in unpredictable behavior.
Upon further consideration, while summing up at the end of this response, I realized that the compiler may not be able to accurately predict the necessary stack size for objects created in the calling function and initialized in a called function, and it would not be possible to dynamically expand the stack frame if the execution had passed to another function. These considerations make my whole idea impossible.
That said, I want to address the workarounds that solve my iterator example.
I had to abandon the idea of using auto like this:
for (auto i=bindpack.begin(); !i.end(); ++i)
Having abandoned auto, and realizing that it's more sensible to explicitly name the variable anyway (if the iterator is different enough to require a new class, it's better to name it to avoid confusion) , I am using this constructor:
BindPackIterator(BindPack &ref) : m_ref_pack(ref), m_index(0) { }
in order to be able to write:
for (BindPackIterator i=bindpack; !i.end(); ++i)
preferring to initialize with an assignment. I used to do this when I was last heavily using C++ in the late 1990's, but it's not been working for me recently. The compiler would ask for a copy operator I didn't want to define for reasons stated above. Now I think that problem was due to my collection of constructors and assignment operators I define to pass the -Weffc++ test. Using simplified classes for this example allowed it to work.
Another workaround for an object more complicated than an iterator might be to use a tuple for the constructor argument for objects that need multiple variables to initialize. There could be a casting operator that returns the necessary tuple from the class that initializes the object.
The constructor could look like:
FancyObject(BigHairyTuple val) : m_data1(get<0>(val)), m_data2(get<1>(val), etc
and the contributing object would define this:
class Foo
{
...
operator BigHairyTuple(void) {
return BigHairyTuple(val1, val2, ...);
}
};
to allow:
FancyObject fo = foo;
I haven't tested this specific example, but I'm working with something similar and it seems likely to work, with some possible minor refinements.

Are all the std::move()-based std::swap() implementations I'm seeing buggy? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What can I do with a moved-from object?
For example, see this code:
template<class T>
void swap(T& a, T& b)
{
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
Is it just me, or is there a bug here? If you move a into tmp, then doesn't a become invalid?
i.e. Shouldn't the move-assignment to a from b be a move-constructor call with placement new instead?
If not, then what's the difference between the move constructor and move assignment operator?
template<class T>
void swap(T& a, T& b)
{
T tmp(std::move(a));
new(&a) T(std::move(b));
new(&b) T(std::move(tmp));
}
When you move data out of an object, the intended semantics is that the object that was moved from ends up in an unspecified but valid state. That means that you can't predict anything about what state the object will be in other than that it will be a well-formed object. This is not quite the same as "this object is dead and gone." Moving data out of an object doesn't end the object's lifetime - it just changes its state to something unspecified - and consequently it's perfectly safe to assign that object a new value.
As a result, the initial version of the swap function is safe. After moving data from a, that object holds some unspecified "safe but unpredictable" value. This value is then overwritten when move-assigning it the value of b.
That second version is unsafe, because the lifetime of a has not ended before you try to construct a new object on top of it. This leads to undefined behavior.
Hope this helps!
a will still be valid. The data within a will not be reliable any more though.
You are not deallocating a when you move its resources, so it's perfectly fine to move new resource to a.
Moving does not make an object invalid. Rather, it remains in a valid but indeterminate state in general. Specific classes have additional guarantees; for example, std::unique_ptr guarantees that it will be null after being moved from.
Remaining a valid object means in particular that it is perfectly fine to assign to the object, which is what the original code does.
Your own proposed solution is heavily broken: When you placement-construct a new object on top of the old one, the lifetime of the old object ends. However, if the destructor of the class has effects, then omitting to call the destructor is undefined behaviour.
Moreover, if you did correctly call the destructor first, but then encountered an exception in the constructor, you'd be in trouble, as you now don't have a valid object which needs to be destroyed at scope exit. Here's a related question of mine on this topic.

C++ object return

TestObject getObject(){
TestObject a(5.0f);
return a;
}
int main(){
TestObject a = getObject();
}
Am I right in saying that in C++ a returned object will not have it's destructor called as it is returned. Is the memory that the object took up in the function call simply deleted without running the destructor?
Ok a specific example..
#include <iostream>
class Test{
public:
Test(){};
~Test(){std::cout << "Goodbye cruel world\n";}
};
Test getAnObject(){
Test a;
return a;
}
int main(){
Test a = getAnObject();
}
If I run this the destructor is run just once (not for the local object in getAnObject()). Can I assume this will always be the case?
#include <iostream>
class Test{
public:
Test(){};
~Test(){std::cout << "Goodbye cruel world\n";}
};
Test getAnObject(){
Test a;
Test b;
int i = 0;
if (i){
return a;
}else{
return b;
}
}
int main(){
Test a = getAnObject();
}
Following the RVO guide this test has the destructor run on both objects in getanobject() and in the main function. Is this a case where I should always implement rule of three to ensure consistent behaviour?
If I run this the destructor is run just once (not for the local object in getAnObject()). Can I assume this will always be the case?
For correctness? No. For efficiency? Yes. -ish.
To elaborate: strictly speaking, the local object will be copied when returning from the function. The local storage will then be cleaned up by calling the local object’s destructor.
However, the compiler is free to generate different code that yields the same observable behaviour. In particular, the standard grants the compilers the right to elide the copying of the return value, and reuse the same storage location for both objects (the local object and the receiving object of the return value). In doing so, the compiler might not need to call the copy constructor, nor the destructor (since it’s reusing the same memory location).
However, this optimization (called “named return value optimization”, NRVO) is not guaranteed by the standard (and in fact it’s not possible to perform everywhere). You cannot assume that it will happen for correctness. In particular, your object still needs a well-defined copy constructor and destructor, otherwise the program is ill-formed.
On the other hand, you can reasonably expect all modern compilers to perform this optimization where ever it is possible. You can therefore (usually) rely on this optimization from a performance point of view.
It is implementation based. It is knows as Return Value Optimization technique. Check this out for more info:
http://en.wikipedia.org/wiki/Return_value_optimization
getObject() would return a copy of a. Here is what happens if the compiler does not do any optimization. A temporary copy of a will be created using the copy constructor of TestObject. Then the original a will be destroyed, and its destructor will be called, and then the temporary object will be copied into the local variable a in the main() function. The temporary will then also be destroyed, and its destructor will be called.
Since the return value of getObject() is immediately assigned to a variable in this particular case, a modern compiler will probably be able to optimize away at least one of the copy operations.
getObject() would return a copy of a, and the original object created in getObject is destroyed on exiting the function, but there can be Return Value Optimization (depends on the compiler you're using).
Besides the mismatched return types in the example, you are probably looking for return value optimization, or more general, copy elision. If I remember correctly, the copy elision rules are even specified in the C++ standard, although somewhat vague.
Is the memory that the object took up in the function call simply deleted without running the destructor?
No. With optimizations disabled, the local object will be destructed (and the destructor invoked). If a copy-elision optimization takes place, the local object will really just be a "reference" (note the quotes) for the one in main - in that case the destructor will not be run within the function, but the memory will not be de-allocated either.
In getObject, you are creating TestObject on the stack, so the return value is invalid. To create an object on the heap, use "new". I don't believe the destructor is called when the method's scope is exited, I think the memory on the stack is simply reclaimed.