Copy constructor confusion - c++

Could anyone explain me the reason why is in this code defined MyClass ( const MyClass & src ) { m_X = src . m_X; } ? Without this line of code it works fine as well and gives the same output which is 32 in this case. What's the difference between having it in and not? I read that copy constructor is made automatically but when you have defined pointer in the class you should define it but i don't get why in this case.
Code below:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass ( int x ) : m_X ( new int ( x ) ) {}
MyClass ( const MyClass &src )
{
m_X = src.m_X;
}
void print ( void ) const
{
cout << *m_X;
}
private:
int * m_X;
};
int main ( void )
{
MyClass a ( 32 ), c = a;
c.print ();
return 0;
}

The default copy constructor as well as your copy constructor does a member wise copy (or shallow copy). In this case you have a pointer which value is the address of where the data is located. This address what is copied.
As noted in other posts you will need to manage pointers a little better.

The problem with the compiler generted one (and yours) is that it copies the pointer. You now have two pointers c.m_x and a.m_x both pointing at the same heap allocated object. Who owns it? What happens if you delete a, it should delete the memory it allocated (you incorrectly dont do this) , but c is still poining at it.
For this reason there is std::shared_ptr. It is designed for this case, it does the Right Thing By Magic
Replace int * m_X by std::shared_ptr<int> m_X

The reason you get the same output is you are doing a shallow copy just like the compiler would do. It is not enough just to copy a pointer. You need to create a new pointer and then set its value to be a copy of what you are copying from. A proper constructor would look like
MyClass ( const MyClass & src ) : m_X(new int(*src.m_X) {}
Now the copy has its own independent pointer that has the same value.
Also note that you need a destructor to delete the memory and a proper copy assignment operator as the default copy assignment operator will do the same thing as the default copy constructor.

Related

Copy constructor in C++ for later use in a function

I looked through different thread and I have a hard time understanding how to utilize copy constructor.
If I want to manipulate my class, but I need to have original values to do so, I have to create a copy.
class object {
public:
int member[5][5];
object(object&); <-- how do we create a copy here?
void manipulate() {
<<-- how do I call it here?
}
};
I've been trying different things such as object copy = object(object&) but it does not work.
object(object&); <-- how do we create a copy here?
One simple way is to omit the declaration, and let C++ compiler do it for you. Since your object does not allocate resources in its constructor's body, C++ can handle creating the copy constructor for you.
<<-- how do I call it here?
Like this:
object copy(*this);
... // Manipulate it here
object( const object &obj )
{
for ( size_t i = 0; i < 5; i++ )
{
for ( int j = 0; j < 5; j++ )
{
member[i][j] = rhs.member[i][j];
}
}
}
Or you can write simply
object( const object &obj ) = default;
because your copy constructor does not do something special.
As for its using then you may use it the following way
object one;
onject two( one );
or
object one;
onject two = one;
or even as
object one;
onject two { one };
or
object one;
onject two = { one };
Also take into account that if you explicitly defined the copy constructor then you should explicitly define the default constructor if you need to have it.
A copy constructor is usually created because you cannot use the one generated by the compiler. In such a case, you will usually copy each member one by one.
For example (written on the fly - not sure if it would even compile with errors/warnings)
class A
{
public:
A();
A(const A& src)
{
m_array = (char*)new char[src.m_arraySize];
memcpy(m_array, src.m_array, src.m_arraySize);
m_arraySize = src.m_arraySize;
}
private:
char* m_array;
int m_arraySize;
};

Copy Constructor classes

Here is my piece of code, please help me understand how to get the copy constructor correct. My class has no copy constructor written for it
test(cosnt test&obj){
////////something
}
But yet when I attempt to make a copy such as test t2(t1); it appears to be copied correctly! Can you please explain to me the reason that the copy seems to work even without an explicit copy constructor?
#include <iostream>
using namespace std;
class test{
int *ptr;
public:
test(int t=0){
ptr=new int;
*ptr=t;
}
void increment(){
(*ptr)++;
}
void display(){
cout<<*ptr<<endl;
}
};
int main(){
test t1;
t1.display();
t1.increment();
t1.display();
test t2(t1);//copy constructor works fine!
t2.display();
t1.increment();
t1.display();
t2.display();
}
C++ is so amazing that when you don't define a copy constructor, move constructor, copy assignment and move assignment for a class, the compiler will have to define them for you (the Standard says so). Of course you can delete them via:
func() = delete;
So for example, if you want to delete the implicit copy constructor in your example you would declare:
test(const test&) = delete;
and as you can see your code won't no longer compile.
The behavior of the implicit copy constructor is the one you would expect: it will copy construct each member of the class to the the other object. In this case it will copy construct the pointer value (not the pointed value), effectively make the two object share the same pointer.
Now, your program is leaking memory right? You have called new but no delete. Let's say you want to clean your resources up by inserting:
delete ptr;
in the destructor (it's a simplified version, of course you would need to define at least a proper move assignment and move constructor). You know what will happen? A nice and beautiful runtime error, telling you that the pointer you are trying to free has not been allocated. The reason why that is, is that both your objects (t1 and t2) destructors a will be called and they will both delete the same pointer. The first correctly and the second erroneously.
For this reason a Rule of three (now Rule of Five) has been established in the C++ community. But you know what? There's even a better rule which is called Rule of Zero. To sums it up (but you should really read about it) it says: don't do RAII yourself. I'd suggest you to follow the latter.
Now, let's discuss a little a bit of new. I'm sure you know this, but I'm here to prevent future damages: you don't need to use new at all in C++. Not anymore, in most cases.
Most of the things pointers once did (optional parameter, pass array by pointer, copyable reference, etc..) has now been "deprecated" (not in the literal sense: they are still there) in favor of sexier approaches (namely boost:optional/std::optional, std::array/std::vector, std::reference_wrapper). And even when all those fails to give you what you need, you can still use std::shared_ptr and std::unique_ptr.
So, please, don't use naked new pointers. Thanks.
If you did not define the copy constructor yourself then the compiler implicitly defines it instead of you. This copy constructor makes member-wise copies of class data members.
Relative to your example of code the implicitly defined copy constructor will copy data member ptr. As the result two or more objects can refer to the same memory.
Your class also needs destructor and the copy assignment operator.
These three specail functions can look the following way for your class
test( const test &rhs ) : ptr( new int( *rhs.ptr ) )
{
}
test & operator =( const test &rhs )
{
if ( this != &rhs )
{
int tmp = new int( *rhs.ptr );
delete ptr;
ptr = tmp;
}
return ( *this );
}
~test()
{
delete ptr;
}
You did not define a copy constructor. Like #jrok said, the compiler-generated default copy constructor only does shallow member-wise copy.
Your copy constructor can look something like:
public:
test(const test& t)
{
ptr = new int;
*ptr = *t.ptr;
}
BTW, you might want to define a destrcutor too to prevent memory leak.
~test()
{
delete ptr;
}

Reassigning variable, delete called twice (C++)

My programming background is the Java world, but I've just started learning C++. I've stumbled across this rather trivial and probably pretty noobish problem that somehow puzzles me as a Java programmer:
I have a class with an array which is initialized via new in the constructor and deleted in the destructor. Now when I create an object of this class and assign another object of this class to the same variable (at least that is what I think it is), the delete[] method in the destructor seems to be called twice when the variables leave the scope (in this case the main() function) (the debugger gives me an _BLOCK_TYPE_IS_VALID assertion failed warning).
Why is that? Why isn't the deconstructor called before I assign a new object to f? How could I explicitely delete Foo(1)? What exactly happens here?
class Foo{
private:
int *field;
public:
Foo(int size){
field = new int[size];
}
~Foo(){
delete[] field;
}
};
int main(){
Foo f = Foo(1);
f = Foo(2);
}
There is something in the C++ world called the Rule Of Three.
A class will automatically generate a destructor, copy constructor, and assignment operator for you.
If you have to manually define one of those functions, you probably have to define all three of them.
In your case, you should define the two copy functions, so that a copy of Foo gets its own copy of field. Add these two functions:
class Foo{
Foo( const Foo &f ) {
size = f.size;
field = new int[size];
std::copy( f.field, f.field + size, field );
}
Foo& operator=( const Foo &f ) {
// Leverage the logic that was already written in the copy constructor
Foo tmp(f);
std::swap( *this, temp );
return *this;
}
};
Note that I'm assuming that you've stored size in the Foo object. You would probably need to store that information anyway in a real-life application
You're not following the rule of three, which is bad. Because the default copy constructor does a shallow copy, all your automatic variables (f and the temporaries) have the field member pointing to the same int, which is destroyed multiple times when the destructor is called.
Implement a proper copy constructor, or use C++ idioms and avoid manual management alltogether - i.e. use a std::vector instead.

Placement new to avoid copy constructor

I have a simple class that contains a pointer to one of it's own members:
struct X {
int val;
int* pVal;
X(int v) : val(v), pVal(&val) {}
}
X x(1);
I have some code like this:
void foo() {
doStuffWith(x);
x = X(2); // completely discard the old value of X, and start again
doStuffWith(x);
}
I'm worried that when x is reassigned, x.pVal will invalidly point to the member of the temporary X(2) if return value optimization does not occur.
I realize I could write a copy constructor to fix this. However, it seems wasteful to do the copy in the first place, rather than constructing the object in the right spot in memory to begin with.
Is it reasonable to use the placement new operator here? Or does this have unintented consequences for destructors?
void foo() {
doStuffWith(x);
new (&x) X(2); // completely discard the old value of X, and start again
doStuffWith(x);
}
The most obvious (and probably most effective) way to make this work is to provide copy assignment and copy construction operators to "do the right thing", something on this general order:
struct X {
int val;
int* pVal;
X(int v) : val(v), pVal(&val) {}
X(X const &other) : val(other.val), pVal(&val) {}
// pVal was already set by ctor, so just ignore it:
X &operator=(X const &other) { val = other.val; return *this; }
// and allow assignment directly from an int:
X &operator=(int n) { val = n; return *this; }
};
Then the rest of the code can just copy/assign X objects without jumping through hoops to prevent corruption.
No
It won't destruct the old value of x, but you're right the the default copy assignment operator won't do what you want either.
For me it seems quite acceptable solution if X's destructor will be called before placement new. It's syntactically allowed even the destructor is not actually specified for the class.
struct X {
int val;
int* pVal;
X(int v) : val(v), pVal(&val) {}
};
X x(1);
void foo() {
doStuffWith(x);
x.~X();
new (&x) X(2);
doStuffWith(x);
}
In this form it is a correct way to reuse memory for any object (but only if the object's ctor can't throw! otherwise UB may happen on program shutdown, i.e. double call of the destructor).
Indeed, the equality of pointers passed and returned from placement new in it non-array form is guaranteed by the standard:
18.6.1.3 Placement forms
...
void* operator new(std::size_t size, void* ptr) noexcept;
Returns: ptr.
Remarks: Intentionally performs no other action.
(and the result of the conversion to void* and then back to the same
pointer type is also guaranteed to be the same as the source pointer)
However, to avoid non-proper use of the class it would be more safe either define copy assignment and copy constructor or declare this class as noncopyable (with deleted ones)
And only the last (noncopyable) case may be regarded as a reason for using placement new.
Although I'm far from promoting placement new for general use, it express the intention to reuse object memory directly and doesn't rely on any optimization. Copy constructor and copy assignment are, of course, more safe, but don't express this intention excactly: no "copy" actually needed, the new object should be constructed in place of the old one.

could you tell me why does this code crash?

So I'm curious of the reason the following code crashes.
Will appreciate help.
#include <iostream>
using namespace std;
class temp
{
public:
temp(int i)
{
intPtr = new int(i);
}
~temp()
{
delete intPtr;
}
private:
int* intPtr;
};
void f (temp fInput)
{
cout << "f called" << endl;
}
int main()
{
temp x = 2;
f(x);
return 0;
}
You are violating The Rule of Three
You maintain a pointer member and you pass a copy of the object to the function f. So, the end result is that you call delete twice on the same pointer.
The crash occurs because of the way you are passing x.
After the scope of the f function, x's destructure will be called and will delete intPtr.
However, that will delete memory that is still in scope for main. Therefor, after return 0 is called, it will try to delete memory that already exists as you are calling delete twice on the same pointer.
To fix this error, change
void f (temp fInput)
to
void f (const temp& fInput)
Alternatively, you could look into using a std::shared_ptr.
The pointer is copied when x is passed (implicit copy constructor) and the destructor is called twice (before the function returns and before main returns), thus the memory is deleted twice.
Use std::shared_ptr<int> here instead instead of a raw int pointer (assuming you want the behavior to be the same, i.e. reference the same int from both temps; otherwise, implement the copy constructor, move constructor and assignment operator yourself).
#include <memory>
class temp {
public:
temp(int i) : intPtr(std::make_shared<int>(i)) {
}
private:
std::shared_ptr<int> intPtr; // reference counting ftw
};
The problem you're hitting here is a double delete. Because you didn't define any copy constructors here C++ is happily doing so for you. The implementation does this by performing a shallow copy of all of the contents.
f(x);
This line works by creating a copy of x and passing it to f. At this point there are 2 temp instances which own a single intPtr member. Both instances will delete that pointer and this is likely what is causing your crash.
To work around this you can take a number of steps
Use a pointer type meant for sharing like shared_ptr<T>
Create an uncallable copy constructor which forces the instance to be passed by ref
An example of #2 is
class temp {
temp(const temp& other);
temp& operator=(const temp& other);
public:
// Same
};
Now the f(x) line simply won't compile because it can't access the necessary copy constructor. It forces it to instead redefine f to prevent a copy.
void f(const temp& fInput) {
...
}