【问题标题】:Understanding Default Move Constructor Definition了解默认移动构造函数定义
【发布时间】:2014-10-07 01:48:39
【问题描述】:

在阅读当前standard 中的move constructor 时,我可以看到以下内容:

12.8 复制和移动类对象

如果类 X 的定义没有显式声明移动构造函数,则当且仅当一个移动构造函数将被隐式声明为默认值

— X 没有用户声明的复制构造函数,
— X 没有用户声明的复制赋值运算符,
— X 没有用户声明的移动赋值运算符,并且
— X 没有用户声明的析构函数。

[ 注意:当移动构造函数没有被隐式声明或显式提供时,否则会调用移动构造函数的表达式可能会调用复制构造函数。 ——尾注]

我认为注释部分清楚地提到了默认移动构造函数的后备将是复制构造函数。为了理解这个概念,我写了一个小程序来理解这个概念。

#include<iostream>
struct handleclass {
public:
   handleclass():length{0}, p{nullptr} {}
    handleclass(size_t l):length{l},p{new int[length]} { }  
    ~handleclass() { delete[] p; }
    size_t length;
    int* p;
 };

handleclass function(void) {
    handleclass x(10);
    return x;
}

int main() {
    handleclass y;
    std::cout<<y.length<<std::endl;
    y = function();
    std::cout<<y.length<<std::endl;   
    
   handleclass a;
   handleclass b(10);
   a = std::move(b);

    return 0;
}

显然这个程序是不正确的,并且由于两个对象对资源的浅拷贝而具有未定义的行为(终止)。但我的重点是了解程序中生成和使用的默认移动构造函数。我希望这个例子有意义。

在上面的程序中,在应该调用移动构造函数的两种情况下,在我看来编译器都在使用默认的复制构造函数。

基于标准中提到的上述规则,我认为我们应该得到编译器错误,因为现在程序显式尝试调用移动构造函数并且用户没有实现也没有编译器生成默认(隐式),因为上述规则不满足? .

但是,这是在没有任何警告/错误的情况下编译并成功运行的。有人可以解释一下默认(隐式)移动构造函数的概念吗?还是我遗漏了什么?

【问题讨论】:

    标签: c++ c++11 move-semantics


    【解决方案1】:

    您忘记了copy elision,这意味着y = function(); 实际上可能不会调用任何复制或移动构造函数;只是x 的构造函数和赋值运算符。

    如该线程所述,某些编译器允许您禁用复制省略。

    我不确定“在两种情况下都应该调用移动构造函数”是什么意思。实际上有 0 种情况应该调用移动构造函数(您的对象没有移动构造函数),还有一种情况可以调用复制构造函数(return 语句)但可以省略。

    您有两种赋值运算符y = function();a = std::move(b);。同样,由于您的类没有移动赋值运算符,因此这些将使用复制赋值运算符。

    如果您从复制构造函数和移动构造函数中将代码添加到 cout 中,这可能有助于您的测试。

    【讨论】:

    • -fno-elide-constructors 选项可用于禁用 g++ 的复制省略
    【解决方案2】:

    确实,由于用户声明的析构函数,没有隐式移动构造函数。

    但是有一个隐式的拷贝构造函数和拷贝赋值运算符;由于历史原因,析构函数不会禁止这些,尽管这种行为已被弃用,因为(正如您所指出的)它通常会给出无效的复制语义。

    它们可用于复制 lvaluesrvalues,因此可用于测试程序中的函数返回(可能被省略)和赋值。如果你想阻止这种情况,那么你必须删除这些函数。

    【讨论】:

      【解决方案3】:

      移动构造函数和移动赋值运算符没有被隐式声明,因为您已经显式定义了析构函数。尽管已隐式声明了复制构造函数和复制赋值运算符(尽管不推荐使用此行为)。

      如果移动构造函数和移动赋值运算符没有被隐式(或显式)声明,它将回退到使用复制等价物。

      当您尝试调用 move-assignment 时,它将回退到使用复制分配。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-01-03
        • 2013-03-16
        • 2012-06-15
        • 1970-01-01
        • 2016-12-16
        • 2015-10-30
        • 2018-02-02
        • 1970-01-01
        相关资源
        最近更新 更多