为什么当移动构造函数被删除时,我的对象没有被复制

Why is my object not being copied when move constructor is deleted?

本文关键字:对象 我的 复制 移动 构造函数 删除 为什么      更新时间:2023-10-16

我试图用这段代码来演示复制构造函数的用法。我的假设是,当我有一个按值返回的函数时,我的编译器将在默认情况下执行对象的移动。但是当move-构造函数不可用时,编译器将进行复制(在c++ 03中,编译器在按值返回时进行复制)。那么,为什么在下面的例子中,编译器试图调用显式删除的move-构造函数,而不是可用的copy-构造函数呢?我在GCC 4.7.2中编译这个。

struct S
{
    S() = default;
    S(S const &) = default;
    S(S&&) = delete;
};
S f() { return S{}; }
int main()
{
    f();
}

prog.cpp: In function ‘S f()’:
prog.cpp:8:18: error: using deleted function ‘S::S(S&&)’
Prog.cpp:5:5: error: declarations here

删除的move成员是邪恶的。它们不是非法的,因为总有一天,有人会找到它们的巧妙用途。但我还没看到有什么好的用途。

删除特殊成员与没有特殊成员是两码事。这一点在move构造函数和move赋值操作符中表现得最为明显。

出现时,无论是删除的、默认的还是用户定义的,move构造函数和move赋值操作符都参与重载解析。这意味着它们与特殊副本成员"竞争"。copy成员通常倾向于左值const,而move成员倾向于右值const。

当从函数返回局部类型时(当局部类型与返回类型是相同的un-cv限定类型时),return语句首先将返回表达式视为右值,只有在找不到合适的构造函数时,才将其视为左值。也就是说,为从函数返回一个局部对象而匹配合适的构造函数是一个两阶段的操作。

如果你根本没有move构造函数(甚至没有删除),但你有一个普通的复制构造函数(接受const &),那么返回语句的右值将匹配复制构造函数。

有移动构造函数时,即使它被标记为删除,返回语句中的右值也会发现移动构造函数比复制构造函数更匹配。

除非你真的知道你在做什么,永远不要删除move成员。如果你不希望你的类型是可移动的,只要不定义move成员,并确保你声明了copy成员,即使拷贝成员是=default 'd。

我想很难从标准中引用什么来删除不做什么?——多元印刷

8.4.3删除定义[dcl.fct.def.delete]

2隐式或隐式引用已删除函数的程序除了声明外,显式地是错误的。[注:此包括隐式或显式调用函数并形成指向函数的指针或指向成员的指针。它甚至适用于表达式中未进行潜在求值的引用。如果一个函数是重载的,只有当函数是重载时才会引用它由过载解析选择。

更新2

12.8复制和移动类对象[class.copy]

9如果类X的定义没有显式声明move构造函数,当且仅当将隐式声明为默认值如果

  • X没有用户声明的复制构造函数,
  • X没有用户声明的拷贝赋值操作符
  • X没有用户声明的move赋值操作符,并且
  • X没有用户声明的析构函数。

[注意:当move构造函数没有隐式声明或的显式提供的表达式,否则将调用Move构造函数可以调用复制构造函数。