What happens if a lambda is moved/destructed while it is running? - c++

Consider:
std::vector<std::function<void()>> vec;
something_unmovable m;
vec.push_back([&vec, m]() {
vec.resize(100);
// things with 'm'
});
vec[0]();
vec.resize(100) will probably cause a re-allocation of the vector, which means that the std::functions will be copied to a new location, and the old ones destroyed. Yet this happens while the old one is still running. This particular code runs because the lambda doesn't do anything, but I imagine this can easily result in undefined behavior.
So, what happens exactly? Is m still accessible from the vector? Or is it that the this pointer of the lambda is now invalid (points to freed memory), so nothing the lambda captures can be accessible, yet if it runs code that doesn't use anything it captures, it's not undefined behavior?
Also, is the case where the lambda is movable any different?

As already covered by other answers, lambdas are essentially syntactic sugar for easily creating types that provide a custom operator() implementation. This is why you can even write lambda invocations using an explicit reference to operator(), like so: int main() { return [](){ return 0; }.operator()(); }. The same rules for all non-static member functions also apply to lambda bodies.
And those rules allow the object being destroyed while the member function is being executed, so long as the member function does not use this afterwards. Your example is an unusual one, the more common example is for a non-static member function executing delete this;. This made it into the C++ FAQ, explaining that it's allowed.
The standard allows this by not really addressing it, as far as I am aware. It describes the semantics of member functions in a way that doesn't rely on the object not being destroyed, so implementations must make sure to let member functions continue executing even if the objects get destroyed.
So to answer your questions:
Or is it that the this pointer of the lambda is now invalid (points to freed memory), so nothing the lambda captures can be accessible, yet if it runs code that doesn't use anything it captures, it's not undefined behavior?
Yes, pretty much.
Also, is the case where the lambda is movable any different?
No, it's not.
The only time where the lambda being movable could possibly matter is after the lambda has been moved. In your example, the operator() continues executing on the original moved-from and then destroyed functor.

You can treat lambda captures like ordinary struct instances.
In your case:
struct lambda_UUID_HERE_stuff
{
std::vector<std::function<void()>> &vec;
something_unmovable m;
void operator()()
{
this->vec.resize(100);
}
};
...and I believe all the same rules apply (as far as VS2013 is concerned).
So, this appears to be another case of undefined behavior. That is, if &vec happens to point to the vector containing the capture instance, and the operations within operator() cause that vector to resize.

Ultimately, there are a lot of details in this question that aren't relevant. We can reduce it to asking about the validity of:
struct A {
something_unmovable m;
void operator()() {
delete this;
// do something with m
}
};
And ask about that behavior. After all, the impact of the resize() is to call the destructor of the object mid-function-call. Whether it's moved-from or copied-from by std::vector doesn't matter - either way it will subsequently be destroyed.
The standard tells us in [class.cdtor] that:
For an object with a non-trivial
destructor, referring to any non-static member or base class of the object after the destructor finishes
execution results in undefined behavior.
So if the destructor of something_unmovable is non-trivial (which would make the destructor of A -- or your lambda -- non-trivial), any reference to m after the destructor is called is undefined behavior. If something_unmovable does have a trivial destructor, then your code is perfectly acceptable. If you don't do anything after the delete this (the resize() in your question), then it's perfectly valid behavior.
Is m still accessible from the vector?
Yes, the functor in vec[0] will still have m in it. It may be the original lambda - or it may be a copy of the original lambda. But there will be an m one way or the other.

Function objects are normally copyable, so your lambda would continue to run without ill effect. If it captures by reference AFAIR the internal implementation will use std::reference_wrapper so that the lambda remains copyable.

Related

Calling destructor in member function

If we are implementing, for example, smart pointers, and we want to do a = std::move(b) --- we need to delete memory to which a is pointing, but can we call destructor inside move assignment operator, instead of copy-pasting destructor's function body?
Is the behavior on calling destructor inside move-assignment defined?
If it's not, are there any better ways dealing with it rather than copy-pasting destructor's body?
You are allowed to call the destructor on this inside a member function and it has well-defined behavior.
However, that behavior involves ending the lifetime of the object *this. After the destructor call you are not allowed to access/use any members of the object anymore. This also has bad consequences in many situations, e.g. if the object has automatic storage duration the destructor will be called a second time on it during scope exit, which would cause undefined behavior.
So that isn't useful for what you want to do.
Although I strongly advice against it, in theory you could then follow the destructor call by construction of a new object at the same storage location via placement-new. However there are some preconditions outside the control of the class on when this is allowed without causing undefined behavior down the line. Under some conditions such a placement-new itself might be undefined behavior, under some conditions the names/references/pointers referring to the old object will not refer to the new one causing undefined behavior if used after the placement-new and under some conditions the lifetime of any parent object that *this is a subobject/member of will also be ended by such an operation, causing undefined behavior if used afterwards.
You can see a demonstration on how this would be implemented, against my advice and under certain (unstated) assumptions, in the standard (draft): https://timsong-cpp.github.io/cppwp/n4868/basic.life#example-2
The linked example and the paragraph preceding it don't spell out all the conditions and possible problems with the approach that I hinted at above. Only the very specific usage of the class/function shown in the example is definitively allowed.
If you just want to reuse code, move the body of the destructor into a new member function and call that one from both locations requiring the same behavior.
Explictly calling destuctor is technically available, you can use this->~Object() in non static method of the class Object.
However this is a bad practice. Consider use these instead.
class Test {
public:
Test() {}
~Test() {
Deallocate();
}
Test(const Test& other) = delete;
Test(Test&& other) {
Deallocate();
// Do sth
}
private:
void Deallocate() {
// Do sth
}
};

Safe to std:move a member?

Have found comparable questions but not exactly with such a case.
Take the following code for example:
#include <iostream>
#include <string>
#include <vector>
struct Inner
{
int a, b;
};
struct Outer
{
Inner inner;
};
std::vector<Inner> vec;
int main()
{
Outer * an_outer = new Outer;
vec.push_back(std::move(an_outer->inner));
delete an_outer;
}
Is this safe? Even if those were polymorphic classes or ones with custom destructors?
My concern regards the instance of "Outer" which has a member variable "inner" moved away. From what I learned, moved things should not be touched anymore. However does that include the delete call that is applied to outer and would technically call delete on inner as well (and thus "touch" it)?
Neither std::move, nor move semantics more generally, have any effect on the object model. They don't stop objects from existing, nor prevent you from using those objects in the future.
What they do is ask to borrow encapsulated resources from the thing you're "moving from". For example, a vector, which directly only stores a pointer some dynamically-allocated data: the concept of ownership of that data can be "stolen" by simply copying that pointer then telling the vector to null the pointer and never have anything to do with that data again. It's yielded. The data belongs to you now. You have the last pointer to it that exists in the universe.
All of this is achieved simply by a bunch of hacks. The first is std::move, which just casts your vector expression to vector&&, so when you pass the result of it to a construction or assignment operation, the version that takes vector&& (the move constructor, or move-assignment operator) is triggered instead of the one that takes const vector&, and that version performs the steps necessary to do what I described in the previous paragraph.
(For other types that we make, we traditionally keep following that pattern, because that's how we can have nice things and persuade people to use our libraries.)
But then you can still use the vector! You can "touch" it. What exactly you can do with it is discoverable from the documentation for vector, and this extends to any other moveable type: the constraints emplaced on your usage of a moved-from object depend entirely on its type, and on the decisions made by the person who designed that type.
None of this has any impact on the lifetime of the vector. It still exists, it still takes memory, and it will still be destructed when the time comes. (In this particular example you can actually .clear() it and start again adding data to a new buffer.)
So, even if ints had any sort of concept of this (they don't; they encapsulate no indirectly-stored data, and own no resources; they have no constructors, so they also have no constructors taking int&&), the delete "touch"ing them would be entirely safe. And, more generally, none of this depends on whether the thing you've moved from is a member or not.
More generally, if you had a type T, and an object of that type, and you moved from it, and one of the constraints for T was that you couldn't delete it after moving from it, that would be a bug in T. That would be a serious mistake by the author of T. Your objects all need to be destructible. The mistake could manifest as a compilation failure or, more likely, undefined behaviour, depending on what exactly the bug was.
tl;dr: Yes, this is safe, for several reasons.
std::move is a cast to an rvalue-reference, which primarily changes which constructor/assignment operator overload is chosen. In your example the move-constructor is the default generated move-constructor, which just copies the ints over so nothing happens.
Whether or not this generally safe depends on the way your classes implement move construction/assignment. Assume for example that your class instead held a pointer. You would have to set that to nullptr in the moved-from class to avoid destroying the pointed-to data, if the moved-from class is destroyed.
Because just defining move-semantics is a custom way almost always leads to problems, the rule of five says that if you customize any of:
the copy constructor
the copy assignment operator
the move constructor
the move assignment operator
the destructor
you should usually customize all to ensure that they behave consistently with the expectations a caller would usually have for your class.

What happens to a lambda that appears to delete itself while it's running? [duplicate]

Consider:
std::vector<std::function<void()>> vec;
something_unmovable m;
vec.push_back([&vec, m]() {
vec.resize(100);
// things with 'm'
});
vec[0]();
vec.resize(100) will probably cause a re-allocation of the vector, which means that the std::functions will be copied to a new location, and the old ones destroyed. Yet this happens while the old one is still running. This particular code runs because the lambda doesn't do anything, but I imagine this can easily result in undefined behavior.
So, what happens exactly? Is m still accessible from the vector? Or is it that the this pointer of the lambda is now invalid (points to freed memory), so nothing the lambda captures can be accessible, yet if it runs code that doesn't use anything it captures, it's not undefined behavior?
Also, is the case where the lambda is movable any different?
As already covered by other answers, lambdas are essentially syntactic sugar for easily creating types that provide a custom operator() implementation. This is why you can even write lambda invocations using an explicit reference to operator(), like so: int main() { return [](){ return 0; }.operator()(); }. The same rules for all non-static member functions also apply to lambda bodies.
And those rules allow the object being destroyed while the member function is being executed, so long as the member function does not use this afterwards. Your example is an unusual one, the more common example is for a non-static member function executing delete this;. This made it into the C++ FAQ, explaining that it's allowed.
The standard allows this by not really addressing it, as far as I am aware. It describes the semantics of member functions in a way that doesn't rely on the object not being destroyed, so implementations must make sure to let member functions continue executing even if the objects get destroyed.
So to answer your questions:
Or is it that the this pointer of the lambda is now invalid (points to freed memory), so nothing the lambda captures can be accessible, yet if it runs code that doesn't use anything it captures, it's not undefined behavior?
Yes, pretty much.
Also, is the case where the lambda is movable any different?
No, it's not.
The only time where the lambda being movable could possibly matter is after the lambda has been moved. In your example, the operator() continues executing on the original moved-from and then destroyed functor.
You can treat lambda captures like ordinary struct instances.
In your case:
struct lambda_UUID_HERE_stuff
{
std::vector<std::function<void()>> &vec;
something_unmovable m;
void operator()()
{
this->vec.resize(100);
}
};
...and I believe all the same rules apply (as far as VS2013 is concerned).
So, this appears to be another case of undefined behavior. That is, if &vec happens to point to the vector containing the capture instance, and the operations within operator() cause that vector to resize.
Ultimately, there are a lot of details in this question that aren't relevant. We can reduce it to asking about the validity of:
struct A {
something_unmovable m;
void operator()() {
delete this;
// do something with m
}
};
And ask about that behavior. After all, the impact of the resize() is to call the destructor of the object mid-function-call. Whether it's moved-from or copied-from by std::vector doesn't matter - either way it will subsequently be destroyed.
The standard tells us in [class.cdtor] that:
For an object with a non-trivial
destructor, referring to any non-static member or base class of the object after the destructor finishes
execution results in undefined behavior.
So if the destructor of something_unmovable is non-trivial (which would make the destructor of A -- or your lambda -- non-trivial), any reference to m after the destructor is called is undefined behavior. If something_unmovable does have a trivial destructor, then your code is perfectly acceptable. If you don't do anything after the delete this (the resize() in your question), then it's perfectly valid behavior.
Is m still accessible from the vector?
Yes, the functor in vec[0] will still have m in it. It may be the original lambda - or it may be a copy of the original lambda. But there will be an m one way or the other.
Function objects are normally copyable, so your lambda would continue to run without ill effect. If it captures by reference AFAIR the internal implementation will use std::reference_wrapper so that the lambda remains copyable.

Should I copy an std::function or can I always take a reference to it?

In my C++ application (using Visual Studio 2010), I need to store an std::function, like this:
class MyClass
{
public:
typedef std::function<int(int)> MyFunction;
MyClass (Myfunction &myFunction);
private:
MyFunction m_myFunction; // Should I use this one?
MyFunction &m_myFunction; // Or should I use this one?
};
As you can see, I added the function argument as a reference in the constructor.
But, what is the best way to store the function in my class?
Can I store the function as a reference since std::function is just a function-pointer and the 'executable code' of the function is guaranteed to stay in memory?
Do I have to make a copy in case a lambda is passed and the caller returns?
My gut feeling says that it's safe to store a reference (even a const-reference). I expect the compiler to generate code for the lambda at compile time, and keep this executable code in 'virtual' memory while the application is running. Therefore the executable code is never 'deleted' and I can safely store a reference to it. But is this really true?
Can I store the function as a reference since std::function is just a function-pointer and the 'executable code' of the function is guaranteed to stay in memory?
std::function is very much not just a function pointer. It's a wrapper around an arbitrary callable object, and manages the memory used to store that object. As with any other type, it's safe to store a reference only if you have some other way to guarantee that the referred object is still valid whenever that reference is used.
Unless you have a good reason for storing a reference, and a way to guarantee that it remains valid, store it by value.
Passing by const reference to the constructor is safe, and probably more efficient than passing a value. Passing by non-const reference is a bad idea, since it prevents you from passing a temporary, so the user can't directly pass a lambda, the result of bind, or any other callable object except std::function<int(int)> itself.
If you pass the function in to the constructor by reference, and don't make a copy of it, you'll be out of luck when the function goes out of scope outside of this object, as the reference will no longer be valid. That much has been said in the previous answers already.
What I wanted to add was that, instead, you could pass the function by value, not reference, into the constructor. Why? well, you need a copy of it anyway, so if you pass by value the compiler can optimize away the need to make a copy when a temporary is passed in (such as a lambda expression written in-place).
Of course, however you do things, you potentially make another copy when you assign the passed in function to the variable, so use std::move to eliminate that copy. Example:
class MyClass
{
public:
typedef std::function<int(int)> MyFunction;
MyClass (Myfunction myFunction): m_myfunction(std::move(myFunction))
{}
private:
MyFunction m_myFunction;
};
So, if they pass in an rvalue to the above, the compiler optimises away the first copy into the constructor, and std::move removes the second one :)
If your (only) constructor takes a const reference, you will need to make a copy of it in the function regardless of how it's passed in.
The alternative is to define two constructors, to deal with lvalues and rvalues separately:
class MyClass
{
public:
typedef std::function<int(int)> MyFunction;
//takes lvalue and copy constructs to local var:
MyClass (const Myfunction & myFunction): m_myfunction(myFunction)
{}
//takes rvalue and move constructs local var:
MyClass (MyFunction && myFunction): m_myFunction(std::move(myFunction))
{}
private:
MyFunction m_myFunction;
};
Now, you handly rvalues differently and eliminate the need to copy in that case by explicitly handling it (rather than letting the compiler handle it for you). May be marginally more efficient than the first but is also more code.
The (probably seen a fair bit around here) relevant reference (and a very good read):
http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
I would suggest you to make a copy:
MyFunction m_myFunction; //prefferd and safe!
It is safe because if the original object goes out of scope destructing itself, the copy will still exist in the class instance.
Copy as much as you like. It is copyable. Most algorithms in standard library require that functors are.
However, passing by reference will probably be faster in non-trivial cases, so I'd suggest passing by constant reference and storing by value so you don't have to care about lifecycle management. So:
class MyClass
{
public:
typedef std::function<int(int)> MyFunction;
MyClass (const Myfunction &myFunction);
// ^^^^^ pass by CONSTANT reference.
private:
MyFunction m_myFunction; // Always store by value
};
By passing by constant or rvalue reference you promise the caller that you will not modify the function while you can still call it. This prevents you from modifying the function by mistake and doing it intentionally should usually be avoided, because it's less readable than using return value.
Edit: I originally said "CONSTANT or rvalue" above, but Dave's comment made me look it up and indeed rvalue reference does not accept lvalues.
As a general rule (especially if you're using these for some highly threaded system), pass by value. There is really no way to verify from within a thread that the underlying object is still around with a reference type, so you open yourself up to very nasty race and deadlock bugs.
Another consideration is any hidden state variables in the std::function, for whom modification is very unlikely to be thread-safe. This means that even if the underlying function call is thread-safe, the std::function wrapper's "()" call around it MAY NOT BE. You can recover the desired behavior by always using thread-local copies of the std::function because they'll each have an isolated copy of the state variables.

Does explicitly calling destructor result in Undefined Behavior here?

In my opinion, the following code (from some C++ question) should lead to UB, but the it seems it is not. Here is the code:
#include <iostream>
using namespace std;
class some{ public: ~some() { cout<<"some's destructor"<<endl; } };
int main() { some s; s.~some(); }
and the answer is:
some's destructor
some's destructor
I learned form c++ faq lite that we should not explicitly call destructor. I think after the explicitly call to the destructor, the object s should be deleted. The program automatically calls the destructor again when it's finished, it should be UB. However, I tried it on g++, and get the same result as the above answer.
Is it because the class is too simple (no new/delete involved)? Or it's not UB at all in this case?
The behavior is undefined because the destructor is invoked twice for the same object:
Once when you invoke it explicitly
Once when the scope ends and the automatic variable is destroyed
Invoking the destructor on an object whose lifetime has ended results in undefined behavior per C++03 §12.4/6:
the behavior is undefined if the destructor is invoked for an object whose lifetime has ended
An object's lifetime ends when its destructor is called per §3.8/1:
The lifetime of an object of type T ends when:
— if T is a class type with a non-trivial destructor (12.4), the destructor call starts, or
— the storage which the object occupies is reused or released.
Note that this means if your class has a trivial destructor, the behavior is well-defined because the lifetime of an object of such a type does not end until its storage is released, which for automatic variables does not happen until the end of the function. Of course, I don't know why you would explicitly invoke the destructor if it is trivial.
What is a trivial destructor? §12.4/3 says:
A destructor is trivial if it is an implicitly-declared destructor and if:
— all of the direct base classes of its class have trivial destructors and
— for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.
As others have mentioned, one possible result of undefined behavior is your program appearing to continue running correctly; another possible result is your program crashing. Anything can happen and there are no guarantees whatsoever.
It's undefined behavior -- but as with any UB, one possibility is that it (more or less) appears to work, at least for some definition of work.
Essentially the only time you need (or want) to explicitly invoke a destructor is in conjunction with placement new (i.e., you use placement new to create an object at a specified location, and an explicit dtor invocation to destroy that object).
From http://www.devx.com/tips/Tip/12684
Undefined behavior indicates that an implementation may behave unpredictably when a program reaches a certain state, which almost without exception is a result of a bug. Undefined behavior can be manifested as a run time crash, unstable and unreliable program state, or--in rare cases--it may even pass unnoticed.
In your case it doesn't crash because the destructor doesn't manipulate any field; actually, your class doesn't have any data members at all. If it did and in destructor's body you manipulated it in any way, you would likely get a run-time exception while calling destructor for the second time.
The problem here is that deletion / deallocation and destructors are separate and independent constructs. Much like new / allocation and constructors. It is possible to do only one of the above without the other.
In the general case this scenario does lack usefulness and just lead to confusion with stack allocated values. Off the top of my head I can't think of a good scenario where you would want to do this (although I'm sure there is potentially one). However it is possible to think of contrived scenarios where this would be legal.
class StackPointer<T> {
T* m_pData;
public:
StackPointer(T* pData) :m_pData(pData) {}
~StackPointer() {
delete m_pData;
m_pData = NULL;
}
StackPointer& operator=(T* pOther) {
this->~StackPointer();
m_pData = pOther;
return this;
}
};
Note: Please don't ever code a class this way. Have an explicit Release method instead.
It most likely works fine because the destructor does not reference any class member variables. If you tried to delete a variable within the destructor you would probably run into trouble when it is automatically called the second time.
Then again, with undefined behavior, who knows? :)
What the main function does is reserving space on the stack, calling some's constructor, and at the end calling some's destructor. This always happens with a local variable, whatever code you put inside the function.
Your compiler won't detect that you manually called the destructor.
Anyway you should never manually call an object's destructor, except for objects created with placement-new.
I believe that if you want your code to be OK you simply need to call placement new and fill it back in before exiting. The call to the destructor isn't the issue, it's the second call to the destructor made when you leave scope.
Can you define the undefined behaviour you expect? Undefined doesn't mean random (or catastrophic): the behaviour of a given program may be repeatable between invocations, it just means you can't RELY on any particular behaviour because it is undefined and there is no guarantee of what will happen.
It is undefined behaviour. The undefined behaviour is the double destructor call and not with the destructor call itself. If you modify your example to:
#include <iostream>
using namespace std;
class some{ public: ~some() { [INSERT ANY CODE HERE] } };
int main() { some s; s.~some(); }
where [INSERT ANY CODE HERE] can be replaced with any arbitrary code. The results have unpredictable side effects, which is why it is considered undefined.