【问题标题】:Return to caller not invoking constructor in C++返回到调用者不在 C++ 中调用构造函数
【发布时间】:2023-01-23 23:52:32
【问题描述】:

我正在学习复制省略并尝试了一些东西来了解它。但是下面的代码发生了意想不到的事情:

template<typename T>
class AutoPtr
{
    T* m_ref;
    public:
    AutoPtr(T* ref)
    {
        printf("Cons called\n");
        m_ref = ref;
    }
    AutoPtr(const AutoPtr& autoPtr)
    {
        printf("Copy called\n");
        m_ref = autoPtr.m_ref;

    }
    AutoPtr operator=(const AutoPtr& autoPtr)
    {
        printf("Assign called\n");
        if(m_ref)
        {
            delete m_ref;
        }
        if(m_ref == autoPtr.m_ref)
        {
            return *this;
        }
    }
    ~AutoPtr()
    {
        delete m_ref;
    }
};

class Reference
{
    public:
        Reference()
        {
            printf("Reference created\n");
        }
        ~Reference()
        {
            printf("Reference deleted\n");
        }
};

AutoPtr<Reference> generateRes()
{
    Reference *ref = new Reference();

     //Scenario 1
    //AutoPtr<Reference> temp{ref};
    //return temp;

    //Scenario 2
    return AutoPtr<Reference>{ref};
}                                                                                                                       
int main()
{
    AutoPtr<Reference> obj1 = generateRes();
    return 0;
}

在上面的代码中,我尝试了两种场景。

  1. 正在初始化临时 AutoPtr 对象,然后返回它。这里,构造函数在 temp 初始化时被调用。但是在main函数中,初始化obj1时,并没有调用constructor。
  2. 直接返回临时对象。在主函数中,初始化了 obj1 并调用了构造函数。

    为什么场景 1 不调用 obj1 的构造函数?是一些编译器优化吗?我知道发生了复制省略并且没有调用复制构造函数,但为什么普通构造函数没有被调用两次?

【问题讨论】:

  • 你为什么认为构造函数应该被调用两次?它在构造 temp 时被调用,并且由于复制省略,没有第二个对象可以调用构造函数。
  • @StefanRiedel 我明白,由于复制省略,复制构造函数不会被调用,但由于 obj1 是全新的对象,它的构造函数应该被调用,对吗?
  • @Rogmier 不,复制省略的全部要点是将两个对象合并为一个对象。如果在构造函数中打印this的值并将其与main中的&amp;obj1的值进行比较,您会发现它们是同一个对象。
  • @Rogmier 不,AutoPtr&lt;Reference&gt; obj1 = generateRes(); 不是赋值而是初始化。复制省略的工作就是确保没有第二个对象必须复制或移动返回值的内容。施工将在目标对象处进行。
  • AutoPtr operator=(const AutoPtr&amp; autoPtr) -- 你为什么要返回一个全新的对象?您应该返回对当前对象的引用:AutoPtr&amp; operator=(const AutoPtr&amp; autoPtr)

标签: c++ constructor c++17


【解决方案1】:

我想您错过的关于 copy elision 的部分就是它的含义。如果没有复制构造发生,新的(调用方)对象是从什么构造的?

没有复制(或移动)意味着有只有一个对象.这意味着构造是在目的地完成的,即在函数内部构造返回值 == 在外部构造返回值。

这也与您的复制赋值运算符 AutoPtr operator=(const AutoPtr&amp;) 无关,因为 AutoPtr&lt;Reference&gt; obj1 = generateRes();initialization

【讨论】:

    猜你喜欢
    • 2010-10-05
    • 2013-10-03
    • 2019-08-12
    • 2014-07-25
    • 1970-01-01
    • 1970-01-01
    • 2015-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多