小飞将 2019-10-05 16:07 采纳率: 66.7%
浏览 465
已采纳

C++ 为什么会调用拷贝构造函数而不是拷贝赋值运算符?

如题

#include <string>

struct X {
   X() { std::cout << "X()" << std::endl; } // 构造函数
   X(const X &x) { std::cout << "X(const X&)" << std::endl; } // 拷贝构造函数
   X &operator=(const X &x) { // 赋值拷贝运算符
      std::cout << "X=" << std::endl;
      return *this;
   }
   ~X() { std::cout << "~X()" << std::endl; }
};

int main() {
   X a;
   X b(a);
   X c = a; // 我期待这里调用拷贝赋值运算符,但实际是调用拷贝构造函数
}

图片说明

  • 写回答

2条回答 默认 最新

  • 斗酒神僧 2019-10-06 14:57
    关注

    首先,区别初始化和赋值。初始化指为处于“混沌”状态的变量提供初始值,构造新的对象。变量初始化之前,它占用的内存区域的数据是未知的、无意义的,所以说它处于“混沌”的状态。严格地说,赋值指以参数值更新对象现有的值,在更新之前可能需要清理现有的资源,比如通过new申请的存储空间。参考下面的代码:

    class StringPtr 
    {
    public:
        StringPtr() : 
            idx(++sidx),
            ps(nullptr)
        {
            cout << "StringPtr(), " << *this << endl;
        }
        StringPtr(const string& s) :
            idx(++sidx),
            ps(new string(s))
        {
            cout << "StringPtr(const string&), " << *this << endl;
        }
        StringPtr(const StringPtr& obj) :
            idx(++sidx)
        {
            assign(obj);
            cout << "StringPtr(const StringPtr&), " << *this << endl;
        }
        StringPtr& operator=(const StringPtr& arg)
        { 
            assign(arg);
            cout << "StringPtr.operator=(const StringPtr&), " << *this << endl;
            return *this;
        }
        ~StringPtr() 
        {
            cout << "~StringPtr(), " << *this << endl;
            if (ps)
            {
                delete ps;
                ps = nullptr;
            }
        }
        friend ostream& operator<<(ostream& os, const StringPtr& sp);
    private:
        void assign(const StringPtr& arg)
        {
            if (&arg != this)
            {
                if (ps)
                {
                    delete ps;                // 释放之前通过new创建的对象
                    ps = nullptr;
                }
                if (arg.ps)
                    ps = new std::string(*arg.ps);
            }
        }
    
        static int sidx;
    
        int idx;                                // 唯一索引号,所有对象的索引不同
        string* ps;
    };
    
    int StringPtr::sidx = 0;
    
    ostream& operator<<(ostream& os, const StringPtr& sp)
    {
        os << "idx : " << sp.idx << ", ps : " << (sp.ps ? *sp.ps : "");
        return os;
    }
    
    void example()
    {
        string s("2019-10-06");
        StringPtr p1(s);                        // 初始化,调用StringPtr(const string&)
        StringPtr p2(p1);                      // 初始化,调用StringPtr(const StringPtr&)
        StringPtr p3 = p1;                    // 初始化,调用StringPtr(const StringPtr&)
        StringPtr p4;                           // 初始化,调用StringPtr().这里没有提供初值,使用默认值.
        p4 = p1;                                 // 拷贝赋值,调用StringPtr.operator=(const StringPtr&)
    }
    

    考虑StringPtr p3 = p1;,此处虽然使用了赋值运算符,但是变量p3尚未初始化,初始化之前它还不是StringPtr类型的对象,如何对它调用拷贝赋值运算呢?

    有关初始化的详细内容,请参考:https://zh.cppreference.com/w/cpp/language/initialization

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 SQL server表计算问题
  • ¥15 C# P/Invoke的效率问题
  • ¥20 thinkphp适配人大金仓问题
  • ¥20 Oracle替换.dbf文件后无法连接,如何解决?(相关搜索:数据库|死循环)
  • ¥15 数据库数据成问号了,前台查询正常,数据库查询是?号
  • ¥15 算法使用了tf-idf,用手肘图确定k值确定不了,第四轮廓系数又太小才有0.006088746097507285,如何解决?(相关搜索:数据处理)
  • ¥15 彩灯控制电路,会的加我QQ1482956179
  • ¥200 相机拍直接转存到电脑上 立拍立穿无线局域网传
  • ¥15 (关键词-电路设计)
  • ¥15 如何解决MIPS计算是否溢出