C++ C++;成员初始化时复制构造函数双调用

C++ C++;成员初始化时复制构造函数双调用,c++,constructor,C++,Constructor,考虑下面的代码,其中正在实例化一个以另一个类作为其成员的组合类: class CopyAble { private: int mem1; public: CopyAble(int n1) : mem1(n1) { cout << "Inside the CopyAble constructor" << endl; } CopyAble(const CopyAble& obj) { cout <&

考虑下面的代码,其中正在实例化一个以另一个类作为其成员的组合类:

class CopyAble {
private:
    int mem1;
public:
    CopyAble(int n1) : mem1(n1) {
        cout << "Inside the CopyAble constructor" << endl;
    }
    CopyAble(const CopyAble& obj) {
        cout << "Inside the CopyAble copy constructor" << endl;
        this->mem1 = obj.mem1;
        return *this;     
    }

    CopyAble& operator=(const CopyAble& obj) {
        cout << "Inside the  CopyAble assignment constructor" << endl;
        this->mem1 = obj.mem1;
    }
    ~CopyAble() {};
};

class CopyAbleComposer {
    private:
        CopyAble memObj;
    public:
        CopyAbleComposer(CopyAble m1) : memObj(m1) {
            cout << "Composing the composer" << endl;
        }
        ~CopyAbleComposer() {}
};

int main()
{
    CopyAble ca(10);
    CopyAbleComposer cac(ca);
    return 0;
}
这意味着可复制复制构造函数将运行两次,一次是在可复制对象被传递到CopyAbleComposer构造函数时运行,另一次是在初始化器memObj(m1)运行时运行

这是复制构造函数的惯用用法吗?复制构造函数在尝试用相同类型的传入对象初始化成员对象时,运行效率很低,而且看起来像陷阱一样,很多C++程序员很容易就不知不觉地陷入其中。
编辑:我不认为这是关于将引用传递到复制构造函数的问题的重复。这里,我们被迫将引用传递到常规构造函数中,以避免重复的对象创建,我的问题是,C++中的类构造函数应该有引用对象,以避免这种重复拷贝?

< p>您应该接受<代码>可拷贝< /C> >参考<代码> CopyAbleComposer(可复制M1)< /C> >,否则将调用复制构造函数来构造参数。还应将其标记为
explicit
,以避免意外调用:

explicit CopyAbleComposer(const CopyAble & m1)

您应该在
CopyAbleComposer(copyablem1)
处通过引用接受
CopyAble
,否则将调用复制构造函数来构造参数。还应将其标记为
explicit
,以避免意外调用:

explicit CopyAbleComposer(const CopyAble & m1)

传递值,关联复制是C++中一个非常广为人知的属性。事实上,过去C++被指责为无用的复制,它是悄无声息发生的,很难避免,并且可能导致性能下降。幽默地提到了这一点,例如:

你不小心创建了十几个你自己的实例,然后把它们全都射到了脚上。提供紧急医疗援助是不可能的,因为你无法分辨哪些是按位拷贝,哪些只是指着别人说,“那边是我。”

C++98 当任何函数/方法被声明为按值接收参数时,就会发生这种复制。不管它是构造函数、“独立”函数还是方法。要避免这种情况,请使用
const
参考:

CopyAbleComposer(const CopyAble& m1) : memObj(m1)
{
    ...
}
注意:即使按如下方式重新排列代码,也始终保留一个副本。这一直是C++中的一大不足。
CopyAbleComposer cac(CopyAble(10)); // initializing mem1 by a temporary object
C++11 引入了C++11,它用一个“move”操作替换了额外的拷贝,这个操作应该比copy更有效:在一个对象动态分配内存的常见情况下,“move”只重新分配一些指针,而“copy”分配和释放内存

为了从移动语义提供的优化中获益,您应该撤消您可能为C++98所做的“优化”,并按值传递参数。此外,初始化
mem1
成员时,应调用移动构造函数:

    CopyAbleComposer(CopyAble m1) : memObj(std::move(m1)) {
        cout << "Composing the composer" << endl;
    }
CopyAble(CopyAble&& obj) {
    cout << "Inside the CopyAble move constructor" << endl;
    this->mem1 = obj.mem1;
}
CopyAbleComposer(可复制m1):memObj(std::move(m1)){

CUT

值传递和关联复制是C++中一个非常广为人知的属性,实际上,过去C++对这种无用的复制进行了批评,它是很难避免的,并且可能导致性能下降。 你不小心创建了十几个你自己的实例,然后把它们全都射到了脚上。提供紧急医疗援助是不可能的,因为你无法分辨哪些是按位复制的,哪些只是指着别人说,“那边是我。”

C++98 当任何函数/方法被声明为按值接收参数时,就会发生这种复制。不管它是构造函数、“独立”函数还是方法。要避免这种情况,请使用
const
引用:

CopyAbleComposer(const CopyAble& m1) : memObj(m1)
{
    ...
}
<>注释:即使你将代码重新排列为一个,一个副本也会一直存在。这是C++长期以来的主要不足。

CopyAbleComposer cac(CopyAble(10)); // initializing mem1 by a temporary object
C++11 引入了C++11,它用一个“move”操作替换了额外的拷贝,这个操作应该比copy更有效:在一个对象动态分配内存的常见情况下,“move”只重新分配一些指针,而“copy”分配和释放内存

要从移动语义提供的优化中获益,您应该撤消您可能对C++98所做的“优化”,并按值传递参数。此外,在初始化
mem1
成员时,您应该调用移动构造函数:

    CopyAbleComposer(CopyAble m1) : memObj(std::move(m1)) {
        cout << "Composing the composer" << endl;
    }
CopyAble(CopyAble&& obj) {
    cout << "Inside the CopyAble move constructor" << endl;
    this->mem1 = obj.mem1;
}
CopyAbleComposer(可复制m1):memObj(std::move(m1)){

无法将
CopyAbleComposer
ctor更改为
CopyAbleComposer(常量CopyAble&m1)
为了避免外部复制。setter不会改变任何东西,您仍然必须向函数传递值。如何传递更为重要。按值传递参数意味着您需要一个副本。当您不想复制时,按引用传递,这是众所周知的。不管您到底想做什么-初始化、构造ng,其他任何内容。您的
Copyable运算符=
调用未定义的行为。当您的函数应该返回
Copyable&
时,您没有返回值。请将
CopyAbleComposer
ctor更改为
CopyAbleComposer(const Copyable&m1)
为了避免外部复制。setter不会改变任何东西,您仍然必须向函数传递值。如何传递更为重要。按值传递参数意味着您需要一个副本。当您不想复制时,按引用传递,这是众所周知的。不管您到底想做什么-初始化、构造ng,其他任何内容。你的
Copyable操作符=
调用未定义的行为。当你的函数应该为此返回
Copyable&
@FrançoisAndrieux时,你没有返回值