为什么当我 return 一个堆分配对象而不是堆栈分配对象时调用复制构造函数?

Why is copy constructor being invoked when I return a heap allocated object but not for stack allocated object?

我有一个 state class 有一步棋 assignment/constructor。副本assingment/constructor设置为delete.

我很困惑为什么在下面的函数中(returns 一个 state 对象)编译并运行得很好,就像这样:

state propagator::PROPAGATE(date & TargetDate)
{
    jmethodID jmid_PROPAGATE = ENV->GetMethodID(this->jcls_PROPAGATOR, "propagate", "(path/to/date;)path/to/state;");
    jobject jobj_PROPAGATED_STATE = ENV->CallObjectMethod(this->jobj_PROPAGATOR, jmid_PROPAGATE, TargetDate.get_DATE_JOBJECT());

    state PROPAGATED_STATE(this->ENV);
    PROPAGATED_STATE.set_STATE_JOBJECT(jobj_PROPAGATED_STATE);
    return PROPAGATED_STATE;

    //state * PROPAGATED_STATE = new state(ENV);
    //PROPAGATED_STATE->set_STATE_JOBJECT(jobj_PROPAGATED_STATE);
    //return *PROPAGATED_STATE;
}

但是当我尝试这个时抱怨复制构造函数已被删除:

state propagator::PROPAGATE(date & TargetDate)
{
    jmethodID jmid_PROPAGATE = ENV->GetMethodID(this->jcls_PROPAGATOR, "propagate", "(path/to/date;)path/to/state;");
    jobject jobj_PROPAGATED_STATE = ENV->CallObjectMethod(this->jobj_PROPAGATOR, jmid_PROPAGATE, TargetDate.get_DATE_JOBJECT());

    //state PROPAGATED_STATE(this->ENV);
    //PROPAGATED_STATE.set_STATE_JOBJECT(jobj_PROPAGATED_STATE);
    //return PROPAGATED_STATE;

    state * PROPAGATED_STATE = new state(ENV);
    PROPAGATED_STATE->set_STATE_JOBJECT(jobj_PROPAGATED_STATE);
    return *PROPAGATED_STATE;
}

编译器输出:

error: use of deleted function ‘state::state(const state&)’

现代编译器足够聪明,可以执行 RVO (What are copy elision and return value optimization?)

state propagator::PROPAGATE(date & TargetDate)
{
    jmethodID jmid_PROPAGATE = ENV->GetMethodID(this->jcls_PROPAGATOR, "propagate", "(path/to/date;)path/to/state;");
    jobject jobj_PROPAGATED_STATE = ENV->CallObjectMethod(this->jobj_PROPAGATOR, jmid_PROPAGATE, TargetDate.get_DATE_JOBJECT());

    state PROPAGATED_STATE(this->ENV);
    PROPAGATED_STATE.set_STATE_JOBJECT(jobj_PROPAGATED_STATE);
    return PROPAGATED_STATE;
}

这就是为什么我们在这里 return 实际上是创建的对象(编译器可以直接为函数的 return 值创建它,以避免复制)。

但在第二种变体中,您试图从 HEAP 中的对象在堆栈中创建对象,而 RVO 或移动不能在此处使用。 这就是它试图执行已删除副本的原因。

state propagator::PROPAGATE(date & TargetDate)
{
    jmethodID jmid_PROPAGATE = ENV->GetMethodID(this->jcls_PROPAGATOR, "propagate", "(path/to/date;)path/to/state;");
    jobject jobj_PROPAGATED_STATE = ENV->CallObjectMethod(this->jobj_PROPAGATOR, jmid_PROPAGATE, TargetDate.get_DATE_JOBJECT());

    state * PROPAGATED_STATE = new state(ENV);
    PROPAGATED_STATE->set_STATE_JOBJECT(jobj_PROPAGATED_STATE);
    return *PROPAGATED_STATE;
}

您还通过丢弃指向堆的指针来泄漏内存,您已经在其中创建了一个对象。