I was experimenting with using unique_ptr and wrote some simple code to check how it works with move semantics.
#include <iostream>
#include <vector>
using namespace std;
class X
{
public:
X(){}
~X() { cout << "Destructor X" << endl; }
void Print() { cout << "X" << endl; }
};
int main()
{
unique_ptr<X> ptr(new X());
ptr->Print();
vector<unique_ptr<X>> v;
v.push_back(move(ptr));
ptr->Print();
v.front()->Print();
return 0;
}
The output is as follows:
X
X
X
Destructor X
My expectation was that the original unique_ptr ptr would be invalidated after the push_back. But the Print() method is called just fine. What would be the explanation for this behavior?
My expectation was that the original unique_ptr ptr would be invalidated after the push_back.
It's set to a null pointer. You can check that by comparing it to nullptr.
But the Print() method is called just fine. What would be the explanation for this behavior?
You're calling a member function on a null pointer, which is undefined behaviour. That member function doesn't actually access any data in the class, so it doesn't crash, but it's still undefined behaviour.
You get similar behaviour for this program, it has nothing to do with unique_ptr:
int main()
{
X x;
X* ptr = &x;
ptr->Print();
ptr = nullptr;
ptr->Print();
}
It appears to work fine because X::Print() doesn't actually read anything from the this pointer. If you change the definition of X::Print() to access some member data in the class you'll probably get a crash due to dereferencing a null pointer.
See When does invoking a member function on a null instance result in undefined behavior? for more information.
What you have is plain undefined behavior. If I replace the contents of main with the following
int main()
{
unique_ptr<X> ptr;
ptr->Print();
cout << (static_cast<bool>(ptr) ? "active\n" : "inactive\n");
}
Both gcc and clang still print
X
inactive
You're calling a member function on a nullptr, and I'm guessing it just happens to work because the member function doesn't actually make use of the this pointer. Change your class definition to:
class X
{
int y = 0;
public:
X(){}
~X() { cout << "Destructor X" << endl; }
void Print() { cout << "y = " << y << endl; }
};
Now your original code should result in a segmentation fault because it'll attempt to dereference nullptr.
As for your expectation that unique_ptr will be invalidated after you move from it, you're absolutely correct. This is guaranteed by the standard.
§20.8.1/4 [unique.ptr]
Additionally, u can, upon request, transfer ownership to another unique pointer u2. Upon completion of such a transfer, the following postconditions hold:
— u2.p is equal to the pre-transfer u.p,
— u.p is equal to nullptr, and
...
Above u & u2 are unique_ptr objects, and p is the pointer to the managed object.
Related
Can somebody explain why I'm getting this error after program ends?
free(): invalid pointer
This is my code:
#include <iostream>
#include <memory>
int main()
{
int a = 3;
std::unique_ptr<int> up(&a);
std::cout << a << std::endl;
std::cout << *up << std::endl;
std::cout << &a << std::endl;
std::cout << up.get() << std::endl;
return 0;
}
std::unique_ptr<int> up(&a);
The whole and entire purpose of std::unique_ptr, the only reason it exists, is so that when it goes out of scope and gets destroyed it automatically deletes whatever it's pointing to (assuming that it hasn't been moved from).
a was instantiated in function local scope, and not dynamic scope, hence attempting to delete, what was not newed, results in undefined behavior, and your crash.
This is a toy model of a unique pointer:
struct toy_ptr {
int* p;
~toy_ptr() { delete p; }
};
("toy" because much more is needed, while this is only what is needed to reproduce your problem)
Now if you do this:
int main() {
int a = 0;
toy_ptr ptr{&a};
}
the toy_ptr takes ownership of a. Owning an object means: the toy_ptr is responsible for deleting it in its destructor. a was not allocated via new, hence attempting to delete it via delete &a invokes undefined behavior.
A unique_ptr is not a toy_ptr, but it also does take ownership of the pointer passed to the constructor and it does attempt to delete it in its destructor.
My friend told me C++ allows us to call a member function even if the instance is destroyed from memory. So I write the code below to verify it, but why the value of a can be extracted even after the object was destroyed? I thought there would be a segment fault.
#include <iostream>
class Foo{
public:
Foo(int a = 0){
std::cout << "created" << std::endl;
this->a = a;
}
~Foo(){
std::cout << "destroyed" << std::endl;
}
Foo *f(){
std::cout << "a=" << a << std::endl;
return this;
}
private:
int a;
};
Foo *iwanttocallf(int i){
return ((Foo)i).f();
}
int main(){
for(int i = 0; i < 3; i++)
iwanttocallf(i)->f();
}
Output from my Macbook Air:
created
a=0
destroyed
a=0
created
a=1
destroyed
a=1
created
a=2
destroyed
a=2
Usually compilers are implementing the member function call as a call to a regular c function with the first argument a pointer to the object (gcc does it like that as far as I know). Now if your pointer is pointing to one destroyed object it doesn't mean that the memory where the a has been stored will be changed, it might be changed. So it is undefined behavior in general. In your case you got a value of a but maybe next time with a different compiler or different code you will crash. Try to use placement new operator then set a value of 'a' = 0 in destructor... and follow the memory where the object is stored.
"My friend told me C++ allows us to call a member function even if the member is destroyed from memory"?
I don't know what your friend is trying to say. But you call member function on some object of a class
unless it's a static member. So, if you delete that object from memory, how could you call any function of that class on that object. It's an undefined behavior.
This is covered in §12.7 [class.cdtor]:
[..] 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.
As other people have told, this involves undefined behavior, and any result is possible. I'll try to explain why you encountered this particular result (stuff working normally).
Objects in C++ are represented by contents of memory. When an object is destroyed, its
destructor is executed, but the memory still contains the previous value. The output operation outputs the value taken from memory (which is now "free" - doesn't belong to any object) - if there is not much stuff going on between the destructor call and the output, the old value will remain.
However, if you change your code to add some calculations, the bug will be evident. For example, I added the following function that simulates some calculations:
int do_stuff()
{
int result = 0;
int x[3] = {0};
for (auto& n: x)
{
n = rand();
result ^= n;
}
return result;
}
I also added a call to this function:
Foo *f(){
std::cout << "foo1: a=" << a << std::endl;
do_stuff();
std::cout << "foo2: a=" << a << std::endl;
return this;
}
I got the output:
foo1: a=0
foo2: a=424238335
This clearly shows that it's not safe to expect anything consistent when dealing with deleted objects.
By the way, some debuggers overwrite the memory that deleted objects occupied with a special value like 0xcdcdcdcd - to make some sense out of this kind of unpredictable behavior. If you execute your code under such a debugger, you will see garbage printed, and will immediately know that your code is buggy.
#include<iostream>
struct Test
{
int n ;
~Test(){}
Test& operator =(int v)
{
n=v;
return *this;
}
};
Test * ptr = nullptr;
void g(Test && p)
{
std::cout << "&&";
}
void g(Test & p)
{
ptr = &p;
std::cout << "&";
}
void f(Test&& t)
{
g(t);
}
void buggy()
{
*ptr = 5;
}
int main()
{
f(Test());
buggy();
std::cin.ignore();
}
Just to be sure, the above code lead to an undefined behavior as we keep address of a tempory ?
Declaring pointer to struct Test* ptr; or "keeping address" as you call it doesn't lead to an undefined behaviour. Using pointers to objects whose lifetime has ended does.
Lifetime of the object created by Test() in main ends right after f(Test()); is executed. After that, whatever you do by using ptr is undefined. This object most likely stays in the memory even after its lifetime has ended, but you shouldn't rely on it.
You should also check out: What are all the common undefined behaviours that a C++ programmer should know about?
Yes, the temporary Test() is allocated on the stack, you take a pointer to it and it's destructor is called after returning. After that, the value of the pointer is still valid, but it points to "undefined" memory so all bets are off on dereferencing the pointer.
Recently, I found an interesting discussion on how to allow read-only access to private members without obfuscating the design with multiple getters, and one of the suggestions was to do it this way:
#include <iostream>
class A {
public:
A() : _ro_val(_val) {}
void doSomething(int some_val) {
_val = 10*some_val;
}
const int& _ro_val;
private:
int _val;
};
int main() {
A a_instance;
std::cout << a_instance._ro_val << std::endl;
a_instance.doSomething(13);
std::cout << a_instance._ro_val << std::endl;
}
Output:
$ ./a.out
0
130
GotW#66 clearly states that object's lifetime starts
when its constructor completes successfully and returns normally. That is, control reaches the end of the constructor body or an earlier return statement.
If so, we have no guarantee that the _val memeber will have been properly created by the time we execute _ro_val(_val). So how come the above code works? Is it undefined behaviour? Or are primitive types granted some exception to the object's lifetime?
Can anyone point me to some reference which would explain those things?
Before the constructor is called an appropriate amount of memory is reserved for the object on Freestore(if you use new) or on stack if you create object on local storage. This implies that the memory for _val is already allocated by the time you refer it in Member initializer list, Only that this memory is not properly initialized as of yet.
_ro_val(_val)
Makes the reference member _ro_val refer to the memory allocated for _val, which might actually contain anything at this point of time.
There is still an Undefined Behavior in your program because, You should explicitly initialize _val to 0(or some value,you choose)in the constructor body/Member Initializer List.The output 0 in this case is just because you are lucky it might give you some other values since _val is left unInitialized. See the behavior here on gcc 4.3.4 which demonstrates the UB.
But as for the Question, Yes indeed the behavior is Well-Defined.
The object's address does not change.
I.e. it's well-defined.
However, the technique shown is just premature optimization. You don't save programmers' time. And with modern compiler you don't save execution time or machine code size. But you do make the objects un-assignable.
Cheers & hth.,
In my opinion, it is legal (well-defined) to initialize a reference with an uninitialized object. That is legal but standard (well, the latest C++11 draft, paragraph 8.5.3.3) recommends using a valid (fully constructed) object as an initializer:
A reference shall be initialized to refer to a valid object or function.
The next sentence from the same paragraph throws a bit more light at the reference creation:
[Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior.]
I understand that reference creation means binding reference to an object obtained by dereferencing its pointer and that probably explains that the minimal prerequisite for initialization of reference of type T& is having an address of the portion of the memory reserved for the object of type T (reserved, but not yet initialized).
Accessing uninitialized object through its reference can be dangerous.
I wrote a simple test application that demonstrates reference initialization with uninitialized object and consequences of accessing that object through it:
class C
{
public:
int _n;
C() : _n(123)
{
std::cout << "C::C(): _n = " << _n << " ...and blowing up now!" << std::endl;
throw 1;
}
};
class B
{
public:
// pC1- address of the reference is the address of the object it refers
// pC2- address of the object
B(const C* pC1, const C* pC2)
{
std::cout << "B::B(): &_ro_c = " << pC1 << "\n\t&_c = " << pC2 << "\n\t&_ro_c->_n = " << pC1->_n << "\n\t&_c->_n = " << pC2->_n << std::endl;
}
};
class A
{
const C& _ro_c;
B _b;
C _c;
public:
// Initializer list: members are initialized in the order how they are
// declared in class
//
// Initializes reference to _c
//
// Fully constructs object _b; its c-tor accesses uninitialized object
// _c through its reference and its pointer (valid but dangerous!)
//
// construction of _c fails!
A() : _ro_c(_c), _b(&_ro_c, &_c), _c()
{
// never executed
std::cout << "A::A()" << std::endl;
}
};
int main()
{
try
{
A a;
}
catch(...)
{
std::cout << "Failed to create object of type A" << std::endl;
}
return 0;
}
Output:
B::B(): &_ro_c = 001EFD70
&_c = 001EFD70
&_ro_c->_n = -858993460
&_c->_n = -858993460
C::C(): _n = 123 ...and blowing up now!
Failed to create object of type A
I'm curious as to whether this code is legal in C++0x. Specifically, will the object declared in the function move_it() be properly moved to the object declared in main()?
#include <iostream>
#include <string>
#include <tr1/memory>
using namespace std;
class x
{
public:
x() { cout << "create " << this << endl; }
~x() { cout << "destroy " << this << endl; }
};
x&& move_it()
{
x r;
return move(r);
}
int main()
{
x n = move_it();
return 0;
}
No, it is returning a reference to a local object, just like with an lvalue reference.
Just return it by value and let x's assumed move constructor pick up the rvalue. When you return by value, the returned object is an rvalue.
If you are lucky, the NRVO optimization will kick in (just like before) and elide the copying anyway.
You are returning a dangling rvalue reference from move_it, which invokes undefined behavior when you access it in main.
If you want to move the object, change the return type to x and get rid of the move:
x move_it()
{
x r;
return r;
}
(Automatic variables are implicitly treated as rvalues when returned from a function.)
As a regular user, anyone not implementing a template library, the only use for r-value references you should make is in implementing move constructors and move assignment.
Check out this video http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Standard-Template-Library-STL-9-of-n