How to avoid unnecessary copying in the following scenario? Class A contains base-type pointer to big object.
class A{
BigBaseClass *ptr;
A(const BigBaseClass& ob);
~A(){delete ptr;}
};
Sometimes I will need object ob to be copied. So I implement virtual cloning:
class BigBaseClass{
virtual BigBaseClass* clone() {return new BigBaseClass(*this);}
};
class BigDerivedClass : BigBaseClass{
virtual BigDerivedClass* clone() {return new BigDerivedClass(*this);}
};
A::A(const BigBaseClass& ob):ptr(ob.clone(){}
But sometimes I will create temporary BigDerivedClass object and use it to construct class A:
A a{BigDerivedClass()};
or
BigDerivedClass f(){
BigDerivedClass b;
/*constructing object*/
return b;
}
A a{f()};
Here there is no need to copy created object and then delete it. It's possible to create this object directly in the heap and store its address in a.ptr.
But it seems unlikely to me that compiler is smart enough to implement copy elision here (or is it?). So what would you suggest to avoid such unnecessary copying?
The compiler will not elide the construction of a copy via clone(): copy elision is only allowed in very specific situations. In all cases where the compiler is allowed to do copy elision the life-times of the objects involved are entirely controlled by the compiler. The four situations are (for details see 12.8 [class.copy] paragraph 8):
Returning a local name by value.
Throwing a local object.
Copying a temporary object which isn't bound to a reference.
When catching by value.
The details when copy-elision is applicable even in these situations are somewhat non-trivial. In any case, return new T(*this); doesn't fit any of these situations.
Typical big objects don't hold their data as part of the object. Instead, they typically hold some data structures which can be moved. If you want to retain the simplicity when using A{f()} without wanting to copy the result of f(), you can get away with a move constructor calling a virtual function transferring the content instead of copying it:
#include <utility>
class BigBaseClass {
public:
virtual ~BigBaseClass() {}
virtual BigBaseClass* clone() const = 0;
virtual BigBaseClass* transfer() && = 0;
};
class A{
BigBaseClass *ptr;
public:
A(BigBaseClass&& obj): ptr(std::move(obj).transfer()) {}
A(BigBaseClass const& obj): ptr(obj.clone()) {}
~A(){delete ptr;}
};
class BigDerivedClass
: public BigBaseClass {
BigDerivedClass(BigDerivedClass const&); // copy the content
BigDerivedClass(BigDerivedClass&&); // transfer the content
BigDerivedClass* clone() const { return new BigDerivedClass(*this); }
BigDerivedClass* transfer() && { return new BigDerivedClass(std::move(*this)); }
};
BigDerivedClass f() {
return BigDerivedClass();
}
int main()
{
A a{f()};
}
Whether move construction does help copying the big objects does depend on how the objects are internally implemented. If they object essentially just contains a couple of pointers to the actual large data, move construction should avoid any relevant cost as transferring the pointers would be negligible compared to setting up the actual data. If the data is actually held within the object the transfer wouldn't really help (although it is generally a bad idea to so anyway for a variety of reasons).
class BigBaseClass
{
public:
virtual ~BigBaseClass() {}
virtual BigBaseClass* clone() const { return new BigBaseClass(*this); }
};
class BigDerivedClass : public BigBaseClass
{
public:
BigDerivedClass* clone() const override { return new BigDerivedClass(*this); }
};
class A
{
BigBaseClass *ptr;
public:
explicit A(BigBaseClass* ob);
~A() { delete ptr; }
};
A::A(BigBaseClass* ob) : ptr(ob)
{
}
int main()
{
A a(new BigDerivedClass);
}
You might think that move semantics would be a good idea, but that doesn't really work in this case since BigBaseClass is a base class, and moving a BigDerivedClass into a BigBaseClass would only move the BigBaseClass parts. But using a smart pointer would be good idea too, unless you are sure that the rest of your code is exception-free.
Related
How do I implement a copy constructor for a class that has a unique_ptr member variable? I am only considering C++11.
Since the unique_ptr can not be shared, you need to either deep-copy its content or convert the unique_ptr to a shared_ptr.
class A
{
std::unique_ptr< int > up_;
public:
A( int i ) : up_( new int( i ) ) {}
A( const A& a ) : up_( new int( *a.up_ ) ) {}
};
int main()
{
A a( 42 );
A b = a;
}
You can, as NPE mentioned, use a move-ctor instead of a copy-ctor but that would result in different semantics of your class. A move-ctor would need to make the member as moveable explicitly via std::move:
A( A&& a ) : up_( std::move( a.up_ ) ) {}
Having a complete set of the necessary operators also leads to
A& operator=( const A& a )
{
up_.reset( new int( *a.up_ ) );
return *this,
}
A& operator=( A&& a )
{
up_ = std::move( a.up_ );
return *this,
}
If you want to use your class in a std::vector, you basically have to decide if the vector shall be the unique owner of an object, in which case it would be sufficient to make the class moveable, but not copyable. If you leave out the copy-ctor and copy-assignment, the compiler will guide your way on how to use a std::vector with move-only types.
The usual case for one to have a unique_ptr in a class is to be able to use inheritance (otherwise a plain object would often do as well, see RAII). For this case, there is no appropriate answer in this thread up to now.
So, here is the starting point:
struct Base
{
//some stuff
};
struct Derived : public Base
{
//some stuff
};
struct Foo
{
std::unique_ptr<Base> ptr; //points to Derived or some other derived class
};
... and the goal is, as said, to make Foo copiable.
For this, one needs to do a deep copy of the contained pointer to ensure the derived class is copied correctly.
This can be accomplished by adding the following code:
struct Base
{
//some stuff
auto clone() const { return std::unique_ptr<Base>(clone_impl()); }
protected:
virtual Base* clone_impl() const = 0;
};
struct Derived : public Base
{
//some stuff
protected:
virtual Derived* clone_impl() const override { return new Derived(*this); };
};
struct Foo
{
std::unique_ptr<Base> ptr; //points to Derived or some other derived class
//rule of five
~Foo() = default;
Foo(Foo const& other) : ptr(other.ptr->clone()) {}
Foo(Foo && other) = default;
Foo& operator=(Foo const& other) { ptr = other.ptr->clone(); return *this; }
Foo& operator=(Foo && other) = default;
};
There are basically two things going on here:
The first is the addition of a user-defined copy constructor of Foo, This is necessary, as the unique_ptr-member iself has no copy constructor. In the declared copy-constructor, a new unique_ptr is created, and the pointer is set to a copy of the original pointee.
In case inheritance is involved, the copy of the original pointee must be done carefully. The reason is that doing a simple copy via std::unique_ptr<Base>(*ptr) in the code above would result in slicing, i.e., only the base component of the object gets copied, while the derived part is missing.
To avoid this, the copy has to be done via the clone-pattern. The
idea is to do the copy through a virtual function clone_impl()
which returns a Base* in the base class. In the derived class,
however, it is extended via covariance to return a Derived*, and
this pointer points to a newly created copy of the derived class. The
base class can then access this new object via the base class pointer
Base*, wrap it into a unique_ptr, and return it via the actual
clone() function which is called from the outside.
Second, by declaring a user-defined copy-constructor as done above, the move constructor gets deleted by the corresponding C++ language rules. The declaration via Foo(Foo &&) = default is thus just to let the compiler know that the standard move constructor still applies.
Try this helper to create deep copies, and cope when the source unique_ptr is null.
template< class T >
std::unique_ptr<T> copy_unique(const std::unique_ptr<T>& source)
{
return source ? std::make_unique<T>(*source) : nullptr;
}
Eg:
class My
{
My( const My& rhs )
: member( copy_unique(rhs.member) )
{
}
// ... other methods
private:
std::unique_ptr<SomeType> member;
};
Daniel Frey mention about copy solution,I would talk about how to move the unique_ptr
#include <memory>
class A
{
public:
A() : a_(new int(33)) {}
A(A &&data) : a_(std::move(data.a_))
{
}
A& operator=(A &&data)
{
a_ = std::move(data.a_);
return *this;
}
private:
std::unique_ptr<int> a_;
};
They are called move constructor and move assignment
you could use them like this
int main()
{
A a;
A b(std::move(a)); //this will call move constructor, transfer the resource of a to b
A c;
a = std::move(c); //this will call move assignment, transfer the resource of c to a
}
You need to wrap a and c by std::move because they have a name
std::move is telling the compiler to transform the value to
rvalue reference whatever the parameters are
In technical sense, std::move is analogy to something like "std::rvalue"
After moving, the resource of the unique_ptr is transfer to another unique_ptr
There are many topics that document rvalue reference; this is a pretty easy one to begin with.
Edit :
The moved object shall remain valid but unspecified state.
C++ primer 5, ch13 also give a very good explanation about how to "move" the object
I suggest use make_unique
class A
{
std::unique_ptr< int > up_;
public:
A( int i ) : up_(std::make_unique<int>(i)) {}
A( const A& a ) : up_(std::make_unique<int>(*a.up_)) {};
int main()
{
A a( 42 );
A b = a;
}
unique_ptr is not copyable, it is only moveable.
This will directly affect Test, which is, in your second, example also only moveable and not copyable.
In fact, it is good that you use unique_ptr which protects you from a big mistake.
For example, the main issue with your first code is that the pointer is never deleted which is really, really bad. Say, you would fix this by:
class Test
{
int* ptr; // writing this in one line is meh, not sure if even standard C++
Test() : ptr(new int(10)) {}
~Test() {delete ptr;}
};
int main()
{
Test o;
Test t = o;
}
This is also bad. What happens, if you copy Test? There will be two classes that have a pointer that points to the same address.
When one Test is destroyed, it will also destroy the pointer. When your second Test is destroyed, it will try to remove the memory behind the pointer, as well. But it has already been deleted and we will get some bad memory access runtime error (or undefined behavior if we are unlucky).
So, the right way is to either implement copy constructor and copy assignment operator, so that the behavior is clear and we can create a copy.
unique_ptr is way ahead of us here. It has the semantic meaning: "I am unique, so you cannot just copy me." So, it prevents us from the mistake of now implementing the operators at hand.
You can define copy constructor and copy assignment operator for special behavior and your code will work. But you are, rightfully so (!), forced to do that.
The moral of the story: always use unique_ptr in these kind of situations.
In Qt, most classes usually have a public wrapper class with a single pointer to a private class. This is for binary compatibility.
https://wiki.qt.io/D-Pointer
However this means that there are a lot of things that need to be implemented by hand. Some people suggest using a QScopedPointer.
How to use the Qt's PIMPL idiom?
However, this does not implement copy and assignment either. Isn't there a smart pointer that will just copy the content of the pointer when it's copied. In essence, it should behaves as if the data in the private class were in the public class.
Qt offers a class just for this purpose: QSharedDataPointer
Used with QSharedData it offers a fast way to implement a class with implicitly shared data and copy on write behavior.
You can also do explicit sharing with QExplicitlySharedDataPointer.
class MyData : public QSharedData
{
public:
MyData (){ }
MyData (const MyData &other)
: QSharedData(other), a(other.a), b(other.b) { }
~MyData () { }
int a;
QString b;
};
class MyClass
{
public:
MyClass() { d = new MyData; }
MyClass(const MyClass&other)
: d (other.d)
{
}
void setA(int a) { d->a = a; } // the function is non const, so accessing d->a will make a copy of MyData if d is shared with another instance (CoW)
int a() const { return d->a; }
private:
QSharedDataPointer<MyData> d;
};
The QScopePointer is the equivalent of the std::unique_ptr, it's a pointer with unique ownership, meaning that it can not be copied.
What usually you do is a deep copy of what the ScopedPointer is pointing to when you implement the copy operation of the facade.
Another solution is to have the pimpl implemented with a shared pointer (QSharedPointer) ; but that means that a facade copied from another will point point to the same pimpl. In some scenarios that can be relevant.
How do I implement a copy constructor for a class that has a unique_ptr member variable? I am only considering C++11.
Since the unique_ptr can not be shared, you need to either deep-copy its content or convert the unique_ptr to a shared_ptr.
class A
{
std::unique_ptr< int > up_;
public:
A( int i ) : up_( new int( i ) ) {}
A( const A& a ) : up_( new int( *a.up_ ) ) {}
};
int main()
{
A a( 42 );
A b = a;
}
You can, as NPE mentioned, use a move-ctor instead of a copy-ctor but that would result in different semantics of your class. A move-ctor would need to make the member as moveable explicitly via std::move:
A( A&& a ) : up_( std::move( a.up_ ) ) {}
Having a complete set of the necessary operators also leads to
A& operator=( const A& a )
{
up_.reset( new int( *a.up_ ) );
return *this,
}
A& operator=( A&& a )
{
up_ = std::move( a.up_ );
return *this,
}
If you want to use your class in a std::vector, you basically have to decide if the vector shall be the unique owner of an object, in which case it would be sufficient to make the class moveable, but not copyable. If you leave out the copy-ctor and copy-assignment, the compiler will guide your way on how to use a std::vector with move-only types.
The usual case for one to have a unique_ptr in a class is to be able to use inheritance (otherwise a plain object would often do as well, see RAII). For this case, there is no appropriate answer in this thread up to now.
So, here is the starting point:
struct Base
{
//some stuff
};
struct Derived : public Base
{
//some stuff
};
struct Foo
{
std::unique_ptr<Base> ptr; //points to Derived or some other derived class
};
... and the goal is, as said, to make Foo copiable.
For this, one needs to do a deep copy of the contained pointer to ensure the derived class is copied correctly.
This can be accomplished by adding the following code:
struct Base
{
//some stuff
auto clone() const { return std::unique_ptr<Base>(clone_impl()); }
protected:
virtual Base* clone_impl() const = 0;
};
struct Derived : public Base
{
//some stuff
protected:
virtual Derived* clone_impl() const override { return new Derived(*this); };
};
struct Foo
{
std::unique_ptr<Base> ptr; //points to Derived or some other derived class
//rule of five
~Foo() = default;
Foo(Foo const& other) : ptr(other.ptr->clone()) {}
Foo(Foo && other) = default;
Foo& operator=(Foo const& other) { ptr = other.ptr->clone(); return *this; }
Foo& operator=(Foo && other) = default;
};
There are basically two things going on here:
The first is the addition of a user-defined copy constructor of Foo, This is necessary, as the unique_ptr-member iself has no copy constructor. In the declared copy-constructor, a new unique_ptr is created, and the pointer is set to a copy of the original pointee.
In case inheritance is involved, the copy of the original pointee must be done carefully. The reason is that doing a simple copy via std::unique_ptr<Base>(*ptr) in the code above would result in slicing, i.e., only the base component of the object gets copied, while the derived part is missing.
To avoid this, the copy has to be done via the clone-pattern. The
idea is to do the copy through a virtual function clone_impl()
which returns a Base* in the base class. In the derived class,
however, it is extended via covariance to return a Derived*, and
this pointer points to a newly created copy of the derived class. The
base class can then access this new object via the base class pointer
Base*, wrap it into a unique_ptr, and return it via the actual
clone() function which is called from the outside.
Second, by declaring a user-defined copy-constructor as done above, the move constructor gets deleted by the corresponding C++ language rules. The declaration via Foo(Foo &&) = default is thus just to let the compiler know that the standard move constructor still applies.
Try this helper to create deep copies, and cope when the source unique_ptr is null.
template< class T >
std::unique_ptr<T> copy_unique(const std::unique_ptr<T>& source)
{
return source ? std::make_unique<T>(*source) : nullptr;
}
Eg:
class My
{
My( const My& rhs )
: member( copy_unique(rhs.member) )
{
}
// ... other methods
private:
std::unique_ptr<SomeType> member;
};
Daniel Frey mention about copy solution,I would talk about how to move the unique_ptr
#include <memory>
class A
{
public:
A() : a_(new int(33)) {}
A(A &&data) : a_(std::move(data.a_))
{
}
A& operator=(A &&data)
{
a_ = std::move(data.a_);
return *this;
}
private:
std::unique_ptr<int> a_;
};
They are called move constructor and move assignment
you could use them like this
int main()
{
A a;
A b(std::move(a)); //this will call move constructor, transfer the resource of a to b
A c;
a = std::move(c); //this will call move assignment, transfer the resource of c to a
}
You need to wrap a and c by std::move because they have a name
std::move is telling the compiler to transform the value to
rvalue reference whatever the parameters are
In technical sense, std::move is analogy to something like "std::rvalue"
After moving, the resource of the unique_ptr is transfer to another unique_ptr
There are many topics that document rvalue reference; this is a pretty easy one to begin with.
Edit :
The moved object shall remain valid but unspecified state.
C++ primer 5, ch13 also give a very good explanation about how to "move" the object
I suggest use make_unique
class A
{
std::unique_ptr< int > up_;
public:
A( int i ) : up_(std::make_unique<int>(i)) {}
A( const A& a ) : up_(std::make_unique<int>(*a.up_)) {};
int main()
{
A a( 42 );
A b = a;
}
unique_ptr is not copyable, it is only moveable.
This will directly affect Test, which is, in your second, example also only moveable and not copyable.
In fact, it is good that you use unique_ptr which protects you from a big mistake.
For example, the main issue with your first code is that the pointer is never deleted which is really, really bad. Say, you would fix this by:
class Test
{
int* ptr; // writing this in one line is meh, not sure if even standard C++
Test() : ptr(new int(10)) {}
~Test() {delete ptr;}
};
int main()
{
Test o;
Test t = o;
}
This is also bad. What happens, if you copy Test? There will be two classes that have a pointer that points to the same address.
When one Test is destroyed, it will also destroy the pointer. When your second Test is destroyed, it will try to remove the memory behind the pointer, as well. But it has already been deleted and we will get some bad memory access runtime error (or undefined behavior if we are unlucky).
So, the right way is to either implement copy constructor and copy assignment operator, so that the behavior is clear and we can create a copy.
unique_ptr is way ahead of us here. It has the semantic meaning: "I am unique, so you cannot just copy me." So, it prevents us from the mistake of now implementing the operators at hand.
You can define copy constructor and copy assignment operator for special behavior and your code will work. But you are, rightfully so (!), forced to do that.
The moral of the story: always use unique_ptr in these kind of situations.
I wrote a Stack and Queue implementation (Linked List based). There is one stack (bigStack). For example, I separate bigStack (example: stackA and stackB). I pop() a node from bigStack, I push() in stackA. In the same way, I push() in stackB. I want bigStack to not change. Therefore I want to clone the bigStack object. How do I clone objects in C++? Or is there another solution to my problem?
class Stack : public List {
public:
Stack() {}
Stack(const Stack& rhs) {}
Stack& operator=(const Stack& rhs) {};
~Stack() {}
int Top() {
if (head == NULL) {
cout << "Error: The stack is empty." << endl;
return -1;
} else {
return head->nosu;
}
}
void Push(int nosu, string adi, string soyadi, string bolumu) {
InsertNode(0, nosu, adi, soyadi, bolumu);
}
int Pop() {
if (head == NULL) {
cout << "Error: The stack is empty." << endl;
return -1;
} else {
int val = head->nosu;
DeleteNode(val);
return val;
}
}
void DisplayStack(void);
};
then...
Stack copyStack = veriYapilariDersi;
copyStack.DisplayStack();
The typical solution to this is to write your own function to clone an object. If you are able to provide copy constructors and copy assignement operators, this may be as far as you need to go.
class Foo
{
public:
Foo();
Foo(const Foo& rhs) { /* copy construction from rhs*/ }
Foo& operator=(const Foo& rhs) {};
};
// ...
Foo orig;
Foo copy = orig; // clones orig if implemented correctly
Sometimes it is beneficial to provide an explicit clone() method, especially for polymorphic classes.
class Interface
{
public:
virtual Interface* clone() const = 0;
};
class Foo : public Interface
{
public:
Interface* clone() const { return new Foo(*this); }
};
class Bar : public Interface
{
public:
Interface* clone() const { return new Bar(*this); }
};
Interface* my_foo = /* somehow construct either a Foo or a Bar */;
Interface* copy = my_foo->clone();
EDIT: Since Stack has no member variables, there's nothing to do in the copy constructor or copy assignment operator to initialize Stack's members from the so-called "right hand side" (rhs). However, you still need to ensure that any base classes are given the opportunity to initialize their members.
You do this by calling the base class:
Stack(const Stack& rhs)
: List(rhs) // calls copy ctor of List class
{
}
Stack& operator=(const Stack& rhs)
{
List::operator=(rhs);
return * this;
};
In C++ copying the object means cloning. There is no any special cloning in the language.
As the standard suggests, after copying you should have 2 identical copies of the same object.
There are 2 types of copying: copy constructor when you create object on a non initialized space and copy operator where you need to release the old state of the object (that is expected to be valid) before setting the new state.
If your object is not polymorphic (and a stack implementation likely isn't), then as per other answers here, what you want is the copy constructor. Please note that there are differences between copy construction and assignment in C++; if you want both behaviors (and the default versions don't fit your needs), you'll have to implement both functions.
If your object is polymorphic, then slicing can be an issue and you might need to jump through some extra hoops to do proper copying. Sometimes people use as virtual method called clone() as a helper for polymorphic copying.
Finally, note that getting copying and assignment right, if you need to replace the default versions, is actually quite difficult. It is usually better to set up your objects (via RAII) in such a way that the default versions of copy/assign do what you want them to do. I highly recommend you look at Meyer's Effective C++, especially at items 10,11,12.
I just need to know if I want to call my copyconstuctor from pImpl class, how will I do it?
For example:
CImpl::SomeFunc()
{
//cloning the caller class instance
caller = new Caller(*this)// I cant do this since its a pImpl class
}
How can i achieve this?
Well after reading your comments, it seems that you want to be able to provide the ability to make copies of Caller class. If so, then in that case you should implement the copy constructor for Caller class, where you can make a hard copy of m_pImpl pointer.
class CallerImpl;
class Caller
{
std::shared_ptr<CallerImpl> m_pImpl;
public:
Caller(Caller const & other) : m_pImpl(other.m_pImpl->Clone()) {}
//...
};
And then you can implement Clone() function in CallerImpl class as:
class CallerImpl
{
public:
CallerImpl* Clone() const
{
return new CallerImpl(*this); //create a copy and return it
}
//...
};
Now you can make copy of Caller:
//Usage
Caller original;
Caller copy(original);