Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么移动构造函数既不声明也不删除?_C++_C++11_User Defined Functions_Move Semantics_Implicit Declaration - Fatal编程技术网

C++ 为什么移动构造函数既不声明也不删除?

C++ 为什么移动构造函数既不声明也不删除?,c++,c++11,user-defined-functions,move-semantics,implicit-declaration,C++,C++11,User Defined Functions,Move Semantics,Implicit Declaration,考虑以下几类 struct with_copy { with_copy() = default; with_copy(with_copy const&) {} with_copy& operator=(with_copy const&) { return *this; } }; struct foo { with_copy c; std::unique_ptr<int> p; }; struct带\u副本{ 带_co

考虑以下几类

struct with_copy {
    with_copy() = default;
    with_copy(with_copy const&) {}
    with_copy& operator=(with_copy const&) { return *this; }
};

struct foo {
    with_copy c;
    std::unique_ptr<int> p;
};
struct带\u副本{
带_copy()=默认值;
with_copy(with_copy const&){
with_copy&operator=(with_copy const&){return*this;}
};
结构foo{
连同副本c;
std::唯一的ptr p;
};
  • 带拷贝的
    是否有拷贝构造函数?对它是明确定义的
  • 带拷贝的
    是否有移动构造函数?否。显式复制构造函数阻止生成它
  • 带拷贝的
    是否有已删除的移动构造函数?不。没有移动构造函数与删除构造函数不同。删除的移动构造函数将尝试移动格式不正确的对象,而不是将其退化为副本
  • 可复制吗?对其复制构造函数用于复制
  • 带拷贝的
    是否可移动?对它的复制构造函数用于移动
。。。现在是棘手的问题

  • foo
    是否有复制构造函数?对它有一个已删除的副本,因为它的默认定义由于调用
    unique\u ptr
    的已删除副本构造函数而格式不正确
  • foo
    是否有移动构造函数?GCC说是,clang说不是
  • foo
    是否有已删除的移动构造函数?GCC和clang都说不
  • foo
    可复制吗?否。已删除其副本构造函数
  • foo
    可移动吗?GCC说是,clang说不是
(当考虑分配而不是构造时,行为类似。)

就我所见,GCC是正确的
foo
应该有一个move构造函数,该构造函数对每个成员执行移动,在
with_copy
的情况下,移动会退化为一个副本。Clang的行为似乎很可笑:我有一个有两个可移动构件的聚合体,而我的聚合体是一块不可移动的砖块


谁说得对?

我不太确定您测试了什么,但它肯定是移动可分配和移动可构造的。诚然,这并不是说移动构造函数或移动赋值是可访问的,只是说从右值进行的构造或赋值是有效的。(clang版本3.5(trunk 196718))和(gcc版本4.9.0 20131031(实验)(gcc))均同意此评估。这是我尝试的完整来源:

#include <iostream>
#include <type_traits>
#include <memory>

struct with_copy {
    with_copy() = default;
    with_copy(with_copy const&) {}
    with_copy& operator=(with_copy const&) { return *this; }
};

struct foo {
    with_copy c;
    std::unique_ptr<int> p;
};

int main()
{
    std::cout << "move constructible: "
              << std::is_move_constructible<foo>::value << '\n';
    std::cout << "move assignable: "
              << std::is_move_assignable<foo>::value << '\n';
    foo f0;
    foo f1 = std::move(f0);
    f0 = std::move(f1);
}
#包括
#包括
#包括
带拷贝的结构{
带_copy()=默认值;
with_copy(with_copy const&){
with_copy&operator=(with_copy const&){return*this;}
};
结构foo{
连同副本c;
std::唯一的ptr p;
};
int main()
{

std::coutC++11,或者更确切地说是n3485,[class.copy]/9:

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

  • X
    没有用户声明的复制构造函数
  • X
    没有用户声明的复制分配运算符
  • X
    没有用户声明的移动分配运算符
  • X
    没有用户声明的析构函数,并且
  • 移动构造函数不会隐式定义为已删除
和/11:

隐式声明的复制/移动构造函数是其类的
内联public
成员。默认副本/ 如果
X
有以下情况,则类
X
的移动构造函数定义为已删除(8.4.3):

  • [……]
  • 对于复制构造函数,为右值引用类型的非静态数据成员,或
  • 对于移动构造函数,一个非静态数据成员或直接或虚拟基类,其类型为 没有移动构造函数,并且不容易复制
由于
with_copy
并非完全可复制,
foo
将没有移动构造函数(它将被定义为已删除,因此不会隐式声明)


C++1y,或者更确切地说是2013-11-12的github回购承诺e31867c0;包括:

/9:

如果类
X
的定义未明确声明移动 构造函数,则仅当且仅当 如果

  • X
    没有用户声明的复制构造函数
  • X
    没有用户声明的复制分配运算符
  • X
    没有用户声明的移动分配运算符,并且
  • X
    没有用户声明的析构函数
和/11:

隐式声明的复制/移动构造函数是
内联public
其类的成员。类
X
如果
X
有以下情况,则定义为已删除(8.4.3):

  • [……]
  • 对于复制构造函数,为右值引用类型的非静态数据成员
定义为已删除的默认移动构造函数将被忽略 过载分辨率(13.3、13.4)


在这里,
foo
将有一个移动构造函数。

从技术上讲,我认为标准的做法是,n3485中的
with_copy
copy构造函数是用户提供的,[class.copy]/11说如果“对于移动构造函数,非静态数据成员或直接或虚拟基类的类型没有移动构造函数且不可复制。”而
with_copy
则不可复制。@DyP没有编译器生成已删除的移动构造函数:S(这些规则很荒谬)因为隐式删除的move构造函数没有声明,/9.Btw,这在C++1y中发生了变化。据我所知,github repo的最新草案说
foo
有一个move构造函数。
std::is\u move\u constructible
被定义为
is\u constructible
,这反过来只是检查
T(declval())
适合于