Consider the following code:
#include <iostream>
#define P_(x) std::cout << x << std::endl
class B {
public:
B() { P_("B::B()"); }
B(const B&) { P_("B::B(const B&)"); }
B(B&&) { P_("B::B(B&&)"); }
~B() { P_("B::~B()"); }
B& operator=(const B&) { P_("B::op=(const B&)"); return *this; }
B& operator=(B&& b) { P_("B::op=(B&&)"); return *this; }
};
class Foo {
public:
void setB(const B& b) { mB = b; }
private:
B mB;
};
B genB() {
return B();
}
int main() {
Foo f;
f.setB(genB());
}
Suppose B is a type that is difficult to copy-construct. I'd like to generate some B (with the function genB) and store it in a Foo. Since genB returns a temporary result, I'd expect that a move constructor would be used.
However, when I run the code, I get this output:
B::B()
B::B()
B::op=(const B&)
B::~B()
B::~B()
This clearly shows that two B's get created and destroyed, but that the second is a copy, and not a move of the first.
What is the best way to get move constructors used whenever possible?
Do I need to call std::move() somewhere?
Do I need a separate overload for a B& and a B&&?
Is there something else entirely that I'm missing?
You could overload that setB function:
class Foo {
public:
void setB(const B& b) { mB = b; }
void setB(B&& b) { mB = std::move(b); }
private:
B mB;
};
Or, you can use the "pass by value" way:
class Foo {
public:
void setB(B b) { mB = std::move(b); }
private:
B mB;
};
Here, the parameter b will be move constructed when possible or copy constructed otherwise.
The first B instance is the one created when creating your Foo instance :
Foo f;
This is because your Foo class has a B member called mB.
The second B instance is the one created by the genB() call.
The assignment operator is called because of the assignment you perform in the Foo::setB function :
mB = b;
Nowhere is there a chance to use a copy or move constructor.
Related
In the following situation:
class A
{
protected:
int m_int;
A() : m_int{-2} {};
public:
A(const A& a) { m_int = a.get(); }
A& operator=(const A& a) { m_int = a.get(); return *this; }
int get() const { return m_int; }
};
class B : public A
{
protected:
using A::m_int;
public:
// same constructors as parent, but public
using A::A;
};
class C : public B
{
public:
// same constructors as parent
using B::B;
C(int x) { m_int = x; }
C(const B& b) { C(b.get()); }
};
class D : public C
{
public:
// same constructors as parent
using C::C;
D(const B& b) { D(b.get()); }
};
int main()
{
C c(5);
D d(c);
return d.get();
}
I would expect for main() to return 5. Instead, it returns -2. It seems it's calling the default constructor of A, whereas I would have expected for it to call the D(const B& b) constructor. What's going on?
Why do I need to provide an explicit constructor for C(const B& b)? I would have guessed for a default behavior to be deduced, for inheritance reasons. What am I missing?
The problem is the constructor in D:
D(const B& b) { D(b.get()); }
This will be the constructor that is called. And it doesn't copy the value from b, instead it creates a new and temporary D object which is promptly destructed as the constructor function exit.
You have the same problem in the corresponding C constructor:
C(const B& b) { C(b.get()); }
You should use a constructor initializer list to delegate to the correct constructor:
D(const B& b) : C(b.get()) {}
Assume a C++ class A with members that can all be copied by the their respective copy constructors. We can rely on the default copy constructor for A to copy its members:
class A {
private:
A(const A&) = default; // We don't really need this line
int a;
B b;
double c;
}
But now let's assume that I want to "extend" (or annotate) the default constructor of A so that in addition to copying its members, it does something else, e.g. writes a line to a log file.
I.e. I'd like to write something like:
class A {
public:
A(const A& a) : A::default(A) {
print("Constructing A\n");
}
private:
// like before
}
Unfortunately that is not correct C++ syntax.
So is there a syntax which allows delegating to a default C++ constructor while explicitly defining the same constructor?
The simplest is to move all members into a base class and write the message in a derived class:
class A_helper {
private:
int a;
B b;
double c;
};
class A : public A_helper {
public:
A() = default;
A(const A& a) : A_helper(a) {
print("Constructing A\n");
}
A(A&& a) : A_helper(std::move(a)) {
print("Constructing A\n");
}
};
You can delegate to the default constructor like you would default-initialize a member variable:
A(const A&) : A()
{
...
}
As often, "We can solve any problem by introducing an extra level of indirection." ( "…except for the problem of too many levels of indirection,"):
struct VerboseA
{
VerboseA() = default;
VerboseA(const VerboseA&) { print("Constructing A\n"); }
VerboseA(VerboseA&&) { print("Constructing A\n"); }
};
And then
class A : VerboseA // EBO (Empty Base Optimisation)
{
private:
A(const A&) = default; // We don't really need this line
int a;
B b;
double c;
};
or in C++20
class A {
private:
A(const A&) = default; // We don't really need this line
[[no_unique_address]]VerboseA verbose; // "EBO" equivalent with attribute
int a;
B b;
double c;
};
I have two classes A and B. I compute a B deterministically from an A. For each A, I want to keep track of the B with my_B for as long as it exists. Once the B is destructed, I want the my_B to be changed to something like nullptr.
class A{
// stuff
public:
B ComputeB(){
if (my_B is null){
B result = B(A);
my_B = B; // some kind of reference
return B(A);
}
else {
return my_B;
}
}
~A(){ /* Do I need a destructor? */ }
private:
WhatTypeHere my_B;
}
When B is destructed, what will cause my_B to refer to nullptr (or the equivalent for WhatTypeHere)?
Using shared_ptr and weak_ptr
In order to keep your B object alive in A as long as it is still in use, you should have a data member in A of type std::weak_ptr<B> this will allow to access the created B object, as long as it is alive.
The return value from computeB would be std::shared_ptr<B> that would be either acquired from the std::weak_ptr<B> member or created, if the latter is holding nullptr.
Thread safety
The decision whether to create or acquire the existing B shall be thread-safe. For this you shall try to fetch the actual B held by the weak_ptr by using the lock() method, then only if the return value is nullptr create a new one.
The code would look like this:
class A {
// stuff
public:
std::shared_ptr<B> ComputeB() {
std::shared_ptr<B> shared_b = my_B.lock();
if (!shared_b){
shared_b = std::make_shared<B>(*this);
my_B = shared_b;
}
return shared_b;
}
// no need for a destructor, unless "stuff" needs one
// ~A(){}
private:
std::weak_ptr<B> my_B;
};
Copy and assignment
The behavior of above class in copying and assignment is problematic, as the default copy constructor and default assignment operator would perform member-wise copy/assignment, which may result with two different A's holding a weak_ptr to the same B. Most probably this is not what you want, especially not if A is mutable (i.e. can change its inner values).
To present suggested code for copy and assignment, let's assume A holds an int member. The code would then look like this:
class A {
int i;
public:
A(int i1): i(i1) {}
void set(int i1) { i = i1; }
std::shared_ptr<B> ComputeB() {
std::shared_ptr<B> shared_b = my_B.lock();
if (!shared_b){
shared_b = std::make_shared<B>(*this);
my_B = shared_b;
}
return shared_b;
}
A(const A& a): i(a.i) {}
A& operator=(const A& a) { i = a.i; return *this; }
~A() {}
private:
std::weak_ptr<B> my_B;
};
Preserving constness
In the code above, the call to ComputeB() cannot be done on a const A object. If we want to support that we need to have a const version of this function. For matter of semantics I prefer renaming this method (both the const and non-const versions) to getB.
To present suggested code that adds the option for calling getB on a const A object we need to present also an example of class B which is able to hold either a const or non-const reference to A. The code would then look like this:
class A {
int i;
// to prevent code duplication for the const and non-const versions
template<typename AType>
static auto getB(AType&& a) {
std::shared_ptr<B> shared_b = a.my_B.lock();
if (!shared_b){
shared_b = std::make_shared<B>(std::forward<AType>(a));
a.my_B = shared_b;
}
return shared_b;
}
public:
A(int i1): i(i1) {}
void set(int i1) { i = i1; }
std::shared_ptr<B> getB() {
return getB(*this);
}
std::shared_ptr<const B> getB() const {
return getB(*this);
}
A(const A& a): i(a.i) {}
A& operator=(const A& a) { i = a.i; return *this; }
~A() {}
private:
mutable std::weak_ptr<B> my_B;
};
And for B:
class B {
union Owner {
A* const ptr;
const A* const const_ptr;
Owner(A& a): ptr(&a) {}
Owner(const A& a): const_ptr(&a) {}
} owner;
public:
B(A& a): owner(a) {}
B(const A& a): owner(a) {}
const A& getOwner() const {
return *owner.const_ptr;
}
A& getOwner() {
return *owner.ptr;
}
};
On the use of union to manage const and non-const versions of the same pointer, see:
Union of const/non-const Object Pointers
Is const-casting via a union undefined behaviour?
Working example: http://coliru.stacked-crooked.com/a/f696dfcf85890977
Private creation token
The code above allows anybody to create objects of B which may lead to undesired possibilities, like creating a non-const B object via the constructor that gets const A& a, resulting with a potential casting from const to non-const when calling getOwner().
A good solution might be to block the creation of B and allow it only from class A. Since the creation is done via make_shared putting B's constructors in the private section of B with a friend declaration for A wouldn't help, it is not A that is calling new B it is make_shared. So we go for a private token approach as in the following code:
class A {
int i;
// only authorized entities can create B
class B_PrivateCreationToken {};
friend class B;
template<typename AType>
static auto getB(AType&& a) {
std::shared_ptr<B> shared_b = a.my_B.lock();
if (!shared_b){
shared_b = std::make_shared<B> (
std::forward<AType>(a),
B_PrivateCreationToken{} );
a.my_B = shared_b;
}
return shared_b;
}
public:
// public part as in above version...
private:
mutable std::weak_ptr<B> my_B;
};
And for B:
class B {
union Owner {
A* const ptr;
const A* const const_ptr;
Owner(A& a): ptr(&a) {}
Owner(const A& a): const_ptr(&a) {}
} owner;
public:
B(A& a, A::B_PrivateCreationToken): owner(a) {}
B(const A& a, A::B_PrivateCreationToken): owner(a) {}
// getOwner methods as in above version...
};
Code: http://coliru.stacked-crooked.com/a/f656a3992d666e1e
You can return a std::shared_ptr from ComputeB(), and make my_B a std::weak_ptr. Something like this:
std::shared_ptr<B> ComputeB() {
if (my_B.expired()) {
auto result = std::make_shared<B>(*this);
my_B = result;
return result;
} else {
return std::shared_ptr<B>(my_B);
}
}
private:
std::weak_ptr<B> my_B;
The idea is that any caller of ComputeB becomes the partial owner of the B instance, which means that it will only be destroyed when all shared_ptrs to it are destroyed. The purpose of the weak_ptr is to point to the B instance without owning it, so the lifetime isn't tied to the A instance at all
I am having trouble writing this fairly simple program. I have two class A and B. B has an object of A. I need to write Copy constructor of B so that two instances of B will have the different instance of A. Is there any neat way to do this? One thing to do is getting all the member variable of parm, creating a new A object and assigning those member variables. But if the class is having more member variables then it is a problem. How to write this in a simple way?
class A
{
public:
int data;
A()
{
}
A(int parm) : data(parm)
{
}
A(const A&parm)
{
this->data = parm.data;
}
A& operator = (const A& parm)
{
if (this != &parm)
{
this->data = parm.data;
}
return *this;
}
~A()
{
cout << "A is destroyed";
}
};
class B
{
public:
A *a;
B()
{
a = new A(10);
}
B(const B&parm)
{
// How to copy the value of parm so this and parm have different A object
// this.a = parm.a --> both this and parm points to same A object
}
B& operator = (const B&parm)
{
if (this != &parm)
{
this->a = parm.a;
}
return *this;
}
~B()
{
// Null check
delete a;
}
};
B's copy constructor needs to allocate a new A object that copies data from the source parm.a member, which you can do using A's copy constructor:
B(const B &parm) {
a = new A(*(parm.a));
}
Also, in B's assignment operator, both A objects are already allocated, so just invoke A's assignment operator:
B& operator=(const B &parm) {
if (this != &parm) {
*a = *(parm.a);
}
return *this;
}
That being said, you can greatly simplify the code if you get rid of the pointer and let the compiler handle the memory allocations and copies for you:
class A {
public:
int data;
A(int parm = 0) : data(parm) { }
~A() { cout << "A is destroyed"; }
};
class B {
public:
A a;
B() : a(10) { }
};
I'm just supposed to be getting used to basic copy constructors.
I assumed I properly placed copy constructors.
But when I try to compile, I keep getting the error "No matching constructor for initialization of B"
I'm a bit confused.
class A {
int valuea;
public:
A(const A&); // copy constructor
int getValuea() const { return valuea; }
void setValuea(int x) { valuea = x; }
};
class B : public A {
int valueb;
public:
B(int valueb);
B(const B&); // copy constructor
int getValueb() const { return valueb; }
void setValueb(int x) { valueb = x; }
};
int main () {
B b1;
b1.setValuea(5);
b1.setValueb(10);
B b2(b1);
cout << "b2.valuea=" << b2.getValuea() << "b2.valueb=" << b2.getValueb() << endl;
return 0;
}
By declaring B(int) and B(const B &), you have disabled the default constructor that is implicitly placed in the class for you when you have no other constructors because for all the compiler knows, you might not want a default constructor, so it can't make assumptions (see here).
Add the following to B, remembering to initialize the base and members with it:
B(){}
In C++11, this works well:
B() = default;
That will allow B to have a default constructor for use when you declare B b1;
The same thing goes for A, too. You have a copy constructor, so there's no longer any default constructor implicitly placed in for you.