I am struggling a little bit with move semantics. I read a lot about that topic, however, there are two concrete problems to which I did not found any answers and, thus, like to present them to you.
First, I have the following exemplary code:
#include <iostream>
#include <cstddef>
class A
{
public:
A *ptr;
virtual ~A()
{
std::cout << "dtor" << std::endl;
delete ptr;
ptr=nullptr;
}
};
main()
{
A x, y;
x.ptr = &y;
}
// compile and link like this with g++: g++ -std=c++0x -lstdc++ code.cc
Class A is able to have a member of itself. I use this "composite pattern" concept to build a hierarchy. However, in this case, when object x is destructed, its destructor deletes the pointer to object y. When finally object y should be destructed, it is already which yields an error... How can I solve this?
The second case looks like this:
main()
{
A x, y;
y = std::move(x);
std::cout << "x.ptr: " << x.ptr << std::endl;
std::cout << "y.ptr: " << y.ptr << std::endl;
}
Here, I can see that both references are equal which means both exists. I though that std::move moves the content from x to y. I would have expected that x.ptr is "empty"....?
Thanks in advance!
Cheers
In the first case, both of your x and y objects are created on stack so they will be destructed automatically. However, your class A's destructor uses delete which assumes that the object referred by ptr was created on heap with new.
So it's an error to set x.ptr to refer an object created on stack (like y). A correct code would be
x.ptr = new A;
This is the danger of raw pointers - you can't differentiate between pointers to dynamically allocated objects (that you have to eventually delete) and "just pointers" (that you can't).
It's better if you use std::unique_ptr<A> instead of raw pointer A*.
It will also call delete my itself, so your delete ptr won't be needed.
As for the second case, for primitive types move is actually just a copy. If you move from int to int, or from ptr to ptr, it's just a copy as there is nothing to optimize with move for primitive types, there is no special "emptying" of the moved-from object. But for your case there are good things called smart pointers that actually do "emptying" (because it guarantees correctness). You guessed it - I'm talking about std::unique_ptr.
So again, if you change your ptr from A* to std::unique_ptr<A> then move will do the job you're looking for.
In two words, std::unique_ptr is your real friend here.
In the first, you create two objects of type A on the stack
A x,y;
then assign the address of y to the member x.ptr. When the objects go out of scope, their destructors are called. This happens in the reverse order of their construction, so it should be
y.~A()
x.~A()
In your case, you manually call delete in the destructor, and this will call delete on an already deleted object when execution x.~A().
This not the only problem in your code:
You call delete on an object on the stack. Calls to deletes should be matched by calls to new. Even better, you should manually call new or delete and use std::unique_ptr and std::shared_ptr`.
When b's destructor is called it will delete ptr which uses an uninitialized value for ptr. The compiler-generated constructor does not initialize the ptr tp nullptr. I know at least one compiler which does this in debug mode but in release mode.
When you use std::move, it will finally call the move constructor (or move assignmnet operator). Since you did not define one manually but you define a destructor, there will be no compiler-generated move constructor. So in your case, it will eventually call the implicit copy-constructor and copy the member values, which is what you are seeing.
Even if you add
class A
{
public:
A(A&& a) = default;
A& operator=(A&& a) = default;
A *ptr;
virtual ~A()
{
std::cout << "dtor" << std::endl;
delete ptr;
ptr=nullptr;
}
};
to request compiler-generated move semantics, it will generate code that does a member-wise move, looking like
A(A&& a): ptr( std::move(a.ptr) ) {}
For a pointer type, this just assigns the value to the new variable and leaves the old variable as is. The standard's requirements on a moved object are quite basic and fulfilled by this.
Related
Have looked at various similar questions here but still can't figure out why the following code does not compile:
// these three are defined somewhere
class A;
std::unique_ptr<A> make_a();
void take_a(std::unique_ptr<A>&&);
int main(){
take_a(make_a()); // this fails
return 0;
}
According to this:
If the default deleter is used, T must be complete at the point in
code where the deleter is invoked, which happens in the destructor,
move assignment operator, and reset member function of
std::unique_ptr.
As far as I understand, none of these (destructor, move assignment operator, nor reset member function) happens in main.
So why does compiler needs the definition of A here?
Since main has a unique_ptr within its scope, realistically it would need to know how to delete the object it holds.
It's possible that take_a doesn't actually take ownership of the object, thus main would need to delete.
main gets a temporary unique_ptr from make_a(), let's call it X. It then passes an rvalue reference to X to take_a. It still has the destroy X. Hence, it has to call the destructor after take_a, even though X would typically be empty at that point.
We need class A description (at least constructor and destructor) in order to create and move std::unique_ptr<A> objects; take_a(make_a()) is creating such object because make_a() is pass-by-value. It first creates a new unique_ptr<A> object, initialize it (using default constructor), and then update its value and returns this new object. Here the default constructor/destructor is being used, which the compiler is unable to find.
#include <bits/stdc++.h>
class A {
public: A() {}
public: ~A() {}
};
std::unique_ptr<A> make_a() {
std::cout << "make";
std::unique_ptr <A> tt = nullptr;
return tt;
}
void take_a(std::unique_ptr<A>&&) {
std::cout << "take";
}
int main(){
take_a(make_a()); // this works now
return 0;
}
Edit: Forgot to add the link. Works the other way too.
I've always assumed that an object begins and ends its lifetime in the same memory location, but I've recently come across a scenario where I need to be sure. Specifically, I'm looking for a guarantee from the standard that no matter what optimizations the compiler performs the address an object is constructed at is the same one that it will have its destructor called from... and that its destructor is, indeed, guaranteed to be called from that location unless the program is terminating.
I've always taken this stuff for granted, but upon closer examination I can't find a guarantee, and there's some language around copy and move elision that I'm not sure how to interpret. I'm hoping that some of the more standards-conversant people here can point me to chapter and verse.
What you are looking for is defined in [intro.object]/1
[...] An object occupies a region of storage in its period of construction ([class.cdtor]), throughout its lifetime, and in its period of destruction ([class.cdtor]).
This means the address cannot change as long as you can access it.
Specifically, I'm looking for a guarantee from the standard that no matter what optimizations the compiler performs the address an object is constructed at is the same one that it will have its destructor called from...
and that its destructor is, indeed, guaranteed to be called from that location unless the program is terminating.
The standard guarantees both for automatic variables and static variables as long as one doesn't do bad things with the objects. However, it does not guarantee either for objects allocated from the free store.
Even for automatic variables, a crafty programmer can subvert the intention through pointer manipulation and explicitly calling the destructor through a pointer.
In addition, the wrong destructor will be called when delete-ing a base class pointer when the base class does not have a virtual destructor. This will be a programming error, not the result of intention to subvert.
Example:
struct Base
{
int b;
};
struct Derived : virtual Base
{
float d;
};
int main()
{
{
Derived d1; // Not a problem.
}
{
Derived d1;
Derived* ptr = &d1;
delete ptr; // Bad. The programmer subverts the program.
// Must not use delete.
}
{
Derived* d2 = new Derived; // The destructor does not get called automatically.
}
{
Derived* d2 = new Derived;
delete d2; // OK. The proper destructor gets called.
}
{
Derived* d2 = new Derived;
Base* ptr = d2;
delete ptr; // Programmer error. The wrong destructor gets called.
}
}
As mentioned by Nathan Oliver, the standard states that:
[...] An object occupies a region of storage in its period of construction ([class.cdtor]), throughout its lifetime, and in its period of destruction ([class.cdtor]).
Compilers respect this, and there are objects (similar to the one you describe) for which it must hold true. Consider std::mutex. A mutex cannot be copied or moved, and the reason for this is that it must remain at the same location in memory for the duration of it's lifetime in order to work.
So how does copy/move elision work?
Copy/move elision works by creating the object where it needs to go. It's that simple.
We can see this behavior for ourselves:
#include <iostream>
struct Foo {
Foo() {
std::cout << "I am at " << (void*)this << '\n';
}
// Delete copy and move, to ensure it cannot be moved
Foo(const Foo&) = delete;
Foo(Foo&&) = delete;
};
Foo getFoo() {
return Foo();
}
int main() {
Foo* ptr = new Foo(getFoo());
std::cout << "Foo ptr is at " << (void*)ptr << '\n';
delete ptr;
}
This code outputs:
I am at 0x201ee70
Foo ptr is at 0x201ee70
And we see that Foo remains at the same location for the duration of it's lifetime, without ever being copied or moved, even though it's being created in dynamically allocated memory.
How does the compiler know where to create an object?
If a function returns a type that is not trivially copyable, then that function takes an implicit parameter representing the memory address where it's supposed to construct the return value.
I'm trying to understand some aspects of C++.
I have written this short programme to show different ways of returning objects from functions in C++:
#include <iostream>
using namespace std;
// A simple class with only one private member.
class Car{
private:
int maxSpeed;
public:
Car( int );
void print();
Car& operator= (const Car &);
Car(const Car &);
};
// Constructor
Car::Car( int maxSpeed ){
this -> maxSpeed = maxSpeed;
cout << "Constructor: New Car (speed="<<maxSpeed<<") at " << this << endl;
}
// Assignment operator
Car& Car::operator= (const Car &anotherCar){
cout << "Assignment operator: copying " << &anotherCar << " into " << this << endl;
this -> maxSpeed = anotherCar.maxSpeed;
return *this;
}
// Copy constructor
Car::Car(const Car &anotherCar ) {
cout << "Copy constructor: copying " << &anotherCar << " into " << this << endl;
this->maxSpeed = anotherCar.maxSpeed;
}
// Print the car.
void Car::print(){
cout << "Print: Car (speed=" << maxSpeed << ") at " << this << endl;
}
// return automatic object (copy object on return) (STACK)
Car makeNewCarCopy(){
Car c(120);
return c; // object copied and destroyed here
}
// return reference to object (STACK)
Car& makeNewCarRef(){
Car c(60);
return c; // c destroyed here, UNSAFE!
// compiler will say: warning: reference to local variable ācā returned
}
// return pointer to object (HEAP)
Car* makeNewCarPointer(){
Car * pt = new Car(30);
return pt; // object in the heap, remember to delete it later on!
}
int main(){
Car a(1),c(2);
Car *b = new Car(a);
a.print();
a = c;
a.print();
Car copyC = makeNewCarCopy(); // safe, but requires copy
copyC.print();
Car &refC = makeNewCarRef(); // UNSAFE
refC.print();
Car *ptC = makeNewCarPointer(); // safe
if (ptC!=NULL){
ptC -> print();
delete ptC;
} else {
// NULL pointer
}
}
The code doesn't seem to crash, and I get the following output:
Constructor: New Car (speed=1) at 0x7fff51be7a38
Constructor: New Car (speed=2) at 0x7fff51be7a30
Copy constructor: copying 0x7fff51be7a38 into 0x7ff60b4000e0
Print: Car (speed=1) at 0x7fff51be7a38
Assignment operator: copying 0x7fff51be7a30 into 0x7fff51be7a38
Print: Car (speed=2) at 0x7fff51be7a38
Constructor: New Car (speed=120) at 0x7fff51be7a20
Print: Car (speed=120) at 0x7fff51be7a20
Constructor: New Car (speed=60) at 0x7fff51be79c8
Print: Car (speed=60) at 0x7fff51be79c8
Constructor: New Car (speed=30) at 0x7ff60b403a60
Print: Car (speed=30) at 0x7ff60b403a60
Now, I have the following questions:
Is makeNewCarCopy safe? Is the local object being copied and destroyed at the end of the function? If so, why isn't it calling the overloaded assignment operator? Does it call the default copy constructor?
My guts tell me to use makeNewCarPointer as the most usual way of returning objects from a C++ function/method. Am I right?
Is makeNewCarCopy safe? Is the local object being copied and destroyed
at the end of the function? If so, why isn't it calling the overloaded
assignment operator? Does it call the default copy constructor?
The important question here is "Is makeNewCarCopy safe?" The answer to that question is, "yes." You are making a copy of the object and returning that copy by-value. You do not attempt to return a reference to a local automatic object, which is a common pitfall among newbies, and that is good.
The answers to the other parts of this question are philisophically less important, although once you know how to do this safely they may become critically important in production code. You may or may not see construction and destruction of the local object. In fact, you probably won't, especially when compiling with optimizations turned on. The reason is because the compiler knows that you are creating a temporary and returning that, which in turn is being copied somewhere else. The temporary becomes meaningless in a sense, so the compiler skips the whole bothersome create-copy-destroy step and simply constructs the new copy directly in the variable where it's ultimately intended. This is called copy elision. Compilers are allowed to make any and all changes to your program so long as the observable behavior is the same as if no changes were made (see: As-If Rule) even in cases where the copy constructor has side-effects (see: Return Value Optimization) .
My guts tell me to use makeNewCarPointer as the most usual way of
returning objects from a C++ function/method. Am I right?
No. Consider copy elision, as I described it above. All contemporary, major compilers implement this optimization, and do a very good job at it. So if you can copy by-value as efficiently (at least) as copy by-pointer, is there any benefit to copy by-pointer with respect to performance?
The answer is no. These days, you generally want to return by-value unless you have compelling need not to. Among those compelling needs are when you need the returned object to outlive the "scope" in which it was created -- but not among those is performance. In fact, dynamic allocation can be significantly more expensive time-wise than automatic (ie, "stack") allocation.
Yes, makeNewCarCopy is safe. Theoretically there will be a copy made as the function exits, however because of the return value optimization the compiler is allowed to remove the copy.
In practice this means that makeNewCarCopy will have a hidden first parameter which is a reference to an uninitialized Car and the constructor call inside makeNewCarCopy will actually initialize the Car instance that resides outside of the function's stack frame.
As to your second question: Returning a pointer that has to be freed is not the preferred way. It's unsafe because the implementation detail of how the function allocated the Car instance is leaked out and the caller is burdened with cleaning it up. If you need dynamic allocation then I suggest that you return an std::shared_ptr<Car> instead.
Yes makeNewCarCopy is safe. And in most cases it is effective as compiler can do certain optimizations like copy elision (and that the reason you do not see assignment operator or copy ctor called) and/or move semantics added by C++11
makeNewCarPointer can be very effective, but is is very dangerous at the same time. The problem is you can easily ignore return value and compiler will not produce any warnings. So at least you should return smart pointer like std::unique_ptr or std::shared_ptr. But IMHO previous method is more preferred and would be at least not slower. Different story if you have to create object on heap by different reason.
here is my c++ code :
class Sample
{
public:
int *ptr;
Sample(int i)
{
ptr = new int(i);
}
~Sample()
{
delete ptr;
}
void PrintVal()
{
cout << "The value is " << *ptr;
}
};
void SomeFunc(Sample x)
{
cout << "Say i am in someFunc " << endl;
}
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
}
it returns me the output like :
Say i am in someFunc
Null pointer assignment(Run-time error)
here As the object is passed by value to SomeFunc the destructor of the object is called when the control returns from the function
should i right ? if yes then why it is happening ? and whats the solution for this ???
Sample is passed by value to SomeFunc, which means a copy is made. The copy has the same ptr, so when that copy is destroyed when SomeFunc returns, ptr is deleted for both objects. Then when you call PrintVal() in main you dereference this invalid pointer. This is undefined behavior. Even if that works then when s1 is destroyed ptr is deleted again, which is also UB.
Also, if the compiler fails to elide the copy in Sample s1= 10; then s1 won't even be valid to begin with, because when the temporary is destroyed the pointer will be deleted. Most compilers do avoid this copy though.
You need to either implement copying correctly or disallow copying. The default copy-ctor is not correct for this type. I would recommend either making this type a value type (which holds its members directly rather than by pointer) so that the default copy-ctor works, or use a smart pointer to hold the reference so that it can manage the by-reference resources for you and the default copy-ctor will still work.
One of the things I really like about C++ is that it's really friendly toward using value types everywhere, and if you need a reference type you can just wrap any value type up in a smart pointer. I think this is much nicer than other languages that have primitive types with value semantics but then user defined types have reference semantics by default.
You usually need to obey the Rule of Three since you have an pointer member.
In your code example to avoid the Undefined Behavior you are seeing:
Replace the need to in first statement by must.
Since SomeFunc() takes its argument by value, the Sample object that you pass to it is copied. When SomeFunc() returns, the temporary copy is destroyed.
Since Sample has no copy constructor defined, its compiler-generated copy constructor simply copies the pointer value, so both Sample instances point to the same int. When one Sample (the temporary copy) is destroyed, that int is deleted, and then when the second Sample (the original) is destroyed, it tries to delete the same int again. That's why your program crashes.
You can change SomeFunc() to take a reference instead, avoiding the temporary copy:
void someFunc(Sample const &x)
and/or you can define a copy constructor for Sample which allocates a new int rather than just copying the pointer to the existing one.
When you pass the argument for the function it's called the copy constructor, but you don't have one so the pointer is not initialised. When it exits the function, the object is calls the destructor to delete the unitialised pointer, so it thows an error.
Instead of
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
}
try to use
int main()
{
Sample* s1= new Sample(10);
SomeFunc(*s1);
s1->PrintVal();
}
I'm running into some strange problems when assigning the reference of a pointer to a variable: the local code works correctly, but it causes memory access errors elsewhere:
//This works fine
Gridcell* g = model.gc;
cout << g->LC_updated << " " << g << endl;
//When I include this, the program crashes elsewhere
//But output from this line is OK
Gridcell gc = *g;
cout << "Var:" << gc.LC_updated << &gc << endl;
(Gridcell is a class, which doesn't have a no-args constructor)
I'm not a C++ expert, and this is a fairly large external library, but I can't understand why an assignment to a locally scoped variable should cause problems elsewhere. Can anyone shed some light on this?
You don't give enough information to solve the problem. There is nothing inherently wrong with the code you've posted.
My guess is that Gridcell lacks a proper copy constructor and so when gc goes out of scope it deletes things that *g is still referring to.
This line of code:
Gridcell gc = *g;
is where the copy constructor is being invoked. It's essentially equivalent to saying this:
Gridcell gc(*g);
which invokes the Gridcell::Gridcell(const Gridcell &) constructor, otherwise known as the copy constructor. The copy constructor is special in that if you don't have one, the compiler will automatically generate one for you. The automatically generated one typically just invokes the copy constructor of each individual member variable, including the pointers. For basic types, like int or Foo *, the copy constructor simply makes an exact copy.
For example, if you have code like this:
class Foo {
public:
Foo() : msg_(new char[30]) { strcpy(msg_, "I'm Foo!"); }
~Foo() { delete [] msg_; }
private:
char *msg_;
};
void aFunction(Foo *aFoo)
{
Foo myfoo = *aFoo;
}
void anotherFunction()
{
Foo localfoo;
aFunction(&localfoo);
}
It will crash. localfoo will allocate character array. The line Foo myfoo = *aFoo will call the copy constructor which will make a straight copy of the pointer. Then the destructor for myfoo will be called and the memory will be freed. Then the destructor for localfoo will be called and the memory will be freed again, resulting in a crash on many systems.
You need to make sure that Gridcell has a proper copy constructor. This is only required if Gridcell manually manages resources, which almost never should be the case. If it the the case for you, you will need The Big Three.
If you need more specific help, post the class definition of Gridcell, along with constructors and destructor, if you have them.
If your intention is not to copy, you can use a reference:
Gridcell & gc = *g;
cout << "Var:" << gc.LC_updated << &gc << endl;
The usage is the same, but it will not create copy.
Is model.gc a local variable?
If so, when it goes out of scope it ceases to exist. And any pointers to it are no longer valid.
#Space_C0wb0y is right.
Imagine that you have attributes in your Gridcell class that are pointers (arrays or objects that are explicitly allocated through new).
When you assgin an object of type Gridcell from another one, the default copy constructor makes a shallow copy. It copies the value of those pointers, but does not create new objects/arrays for the new attributes of yout new object.
If you split
cout << "Var:" << gc.LC_updated << &gc << endl;
in two lines:
cout << "&gc" <<&gc << endl;
cout << "Var:" << gc.LC_updated << endl;
You will probably see that the fault goes to the line where your reference LC_updated (I don't know what is it).
Check your constructors to see how it is being initialized.
This line:
GridCell gc = *g;
Does a copy of the instance pointed by g. If the GridCell does not define a copy-constructor (a constructor of signature GridCell(const GridCell& other)), then a default one is provided by the compiler that does a copy of each member. For member that are of a pointer type, this is just a copy of the pointer, and thus both gc and the instance pointed by g will point to the same memory.
When the gc variable goes out of scope, its destructor is called. If the GridCell class does manage some memory, does not provide a copy-constructor (or it is incorrect), and release the memory in its destructor, then the GridCell instance pointed by g will point to released memory after this point.
Generally, when a class manage some memory, it must override the destructor, the copy-constructor and the assignment operator. This is the rule of three.
Please note that the assignment will also perform slicing if g point to a subclass of GridCell and that can also bring other problems. If you want to use the gc variable as an alias not to have to use *g everywhere, you should consider using a reference (or a const-reference) instead of making a copy (especially if the object does manager lots of memory, copy can be expensive).