为什么当移动构造函数被删除时我的对象不被复制? [英] Why is my object not being copied when move constructor is deleted?

查看:186
本文介绍了为什么当移动构造函数被删除时我的对象不被复制?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用此代码演示使用复制构造函数。我的推测是,当我有一个函数返回值,我的编译器将默认情况下,执行对象的移动。但是当移动构造函数不可用时,编译器将复制(在C ++ 03中,编译器将在返回值的时候复制)。那么为什么在下面的例子中编译器尝试调用显式删除的移动构造函数而不是可用的复制构造函数?我在GCC 4.7.2中编译这个。

  struct S 
{
S默认;
S(S const&)= default;
S(S&&)= delete;
};

S f(){return S {}; }

int main()
{
f();
}




prog.cpp:在函数'S f()'

prog.cpp:8:18:错误:使用已删除的函数'S :: S S&&&& amp;&&&&&&&&&&&&& class =h2_lin>解决方案

删除的移动成员是邪恶的。他们不是非法的,因为有一天,有人会发现他们聪明的用法。但我还没有看到一个很好的用途。



删除一个特殊的成员是不一样的,没有一个特殊的成员。



当存在时,无论是删除,默认还是用户定义,移动构造函数和移动赋值操作操作员参与重载分辨率。这意味着他们与特殊的副本成员竞争。



从函数返回一个局部类型时(当局部类型是相同的un-cv时)复制成员通常偏好const lvalues,作为返回类型的返回类型),返回语句首先将返回表达式视为右值,并且只有当它找不到合适的构造函数时,它才被认为是左值。也就是说匹配用于从函数返回局部对象的正确构造函数是一个两阶段操作。



当你没有移动构造函数(甚至没有删除) ,但你有一个正常的拷贝构造函数(接受一个const&),那么return语句的右值将匹配拷贝构造函数。



do 有一个移动构造函数,即使它被标记为已删除,从返回语句的rvalue将发现move构造函数比复制构造函数更好的匹配。



摘要



除非您真的知道自己正在做什么,否则从不删除移动成员。如果你不想让你的类型是可移动的,只是不要定义移动成员,并确保你声明复制成员,即使复制成员 = default 'd。



更新


很难从标准上提供什么删除
不这样做的报价? - DyP


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


2隐式引用删除的函数或明确指定
的程序,除了声明外,还不成立。 [注意:
包括隐式或显式调用函数,并形成一个
指针或指向成员的指针。它甚至适用于不可能被评估的表达式中的
引用。如果
函数重载,则仅当函数是通过重载分辨率选择的
时才被引用。 - end note]


更新2



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


9如果类X的定义没有明确声明移动
构造函数,一个将隐式声明为默认值if和只有
if




  • X没有用户声明的副本

  • X没有用户声明的复制赋值运算符,

  • X没有用户声明的移动赋值运算符, / li>
  • X没有用户声明的析构函数。



不是隐式声明或
显式提供,否则将调用
move构造函数的表达式可以改为调用复制构造函数。 - end note]



I'm trying to use this code to demonstrate the use of the copy-constructor. My presumption was that when I have a function that returns by value, my compiler will, by default, perform a move of the object. But when the move-constructor is unavailable, the compiler will copy instead (in C++03, the compiler would copy when returning by-value). So why in the following example does the compiler try to call the explicitly-deleted move-constructor instead of the available copy-constructor? I'm compiling this in 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: use of deleted function ‘S::S(S&&)’
prog.cpp:5:5: error: declared here

解决方案

Deleted move members are evil. They are not outlawed, because some day, someone will find a clever use for them. But I haven't seen a good use yet.

Deleting a special member is not the same thing as not having a special member. Nowhere is this more obvious than with the move constructor and move assignment operator.

When present, whether deleted, defaulted, or user-defined, the move constructor and the move assignment operator participate in overload resolution. That means that they "compete" with the special copy members. The copy members will typically favor const lvalues, whereas the move members attract rvalues.

When returning a local type from a function (when the local type is the same un-cv-qualified type as the return type), the return statement first considers the return expression as an rvalue, and only if it can't find a suitable constructor, will it then be considered as an lvalue. I.e. matching the proper constructor for returning a local object from a function is a 2-phase operation.

When you don't have a move constructor at all (not even deleted), but you do have a normal copy constructor (takes a const &), then the rvalue from the return statement will match the copy constructor.

When you do have a move constructor, even it is marked deleted, the rvalue from the return statement will find the move constructor a better match than the copy constructor.

Summary

Unless you really know what you are doing, never delete the move members. If you don't want your type to be movable, just do not define the move members and make sure that you do declare copy members, even if the copy members are =default'd.

Update

I suppose it's hard to provide quotes from the Standard on what delete doesn't do? – DyP

8.4.3 Deleted definitions [dcl.fct.def.delete]

2 A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. [ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not potentially-evaluated. If a function is overloaded, it is referenced only if the function is selected by overload resolution. — end note ]

Update 2

12.8 Copying and moving class objects [class.copy]

9 If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if

  • X does not have a user-declared copy constructor,
  • X does not have a user-declared copy assignment operator,
  • X does not have a user-declared move assignment operator, and
  • X does not have a user-declared destructor.

[Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. — end note ]

这篇关于为什么当移动构造函数被删除时我的对象不被复制?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆