编译器生成的移动构造函数的行为是什么?

Fra*_*ahm 32 c++ move-semantics c++11

是否std::is_move_constructible<T>::value == true暗示T有一个可用的移动构造函数?如果是这样,它的默认行为是什么?

考虑以下情况:

struct foo {
    int* ptr;
};

int main() {
    {       
        std::cout << std::is_move_constructible<foo>::value << '\n';
        foo f;
        f.ptr = (int*)12;
        foo f2(std::move(f));
        std::cout << f.ptr << ' ' << f2.ptr << '\n';
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出是:

1
0000000C 0000000C
Run Code Online (Sandbox Code Playgroud)

我认为那f.ptr应该是nullptr.所以在这种情况下,

  1. f2移动构建?
  2. 如果是这样,rval值不应该失效吗?
  3. 如何知道类的实例是否可以正确移动构造(使旧的实例无效)?

(我正在使用VS11.)

更新

移动构造函数的默认行为与复制构造函数相同,是否正确?如果这是真的,

  1. 我们总是希望移动ctor来窃取移动对象的资源,而默认移动对象的行为并不像预期的那样,那么有一个默认移动ctor的重点是什么?
  2. 我怎么知道一个类是否有自定义移动构造函数(可以保证其行为正常)?

foo f2(std::move(f));当我宣布一个时,似乎调用了copy ctor,参见:

struct foo {
    int* ptr;
    foo() {}
    foo(const foo& other) {
        std::cout << "copy constructed\n";
    }
};

int main() {
    {       
        std::cout << std::is_move_constructible<foo>::value << '\n';
        foo f;
        foo f2(std::move(f));
    }
    system("pause");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在的输出是:

1
copy constructed
Run Code Online (Sandbox Code Playgroud)

如果foo有一个移动构造函数,那么就不会foo f2(std::move(f))调用它?

所以现在我的问题是:如何知道一个类是否有一个移动ctor,如果它有一个,我怎么能明确地调用它?

我要做的是......

template<typename T, bool has_move_ctor>
struct MoveAux;

template<typename T>
struct MoveAux<T, true> {
    static void doMove(T* dest, T* src) {
        new(dest) T(std::move(*src)); //move ctor
    }
};

template<typename T>
struct MoveAux<T, false> {
    static void doMove(T* dest, T* src) {
        new(dest) T(*src); //copy ctor
        src->~T();
    }
};

template<typename T>
inline doMove(T* dest, T* src) {
    MoveAux<T,/*a trait*/>::doMove(dest, src);
}
Run Code Online (Sandbox Code Playgroud)

所以我认为std::is_move_constructible<T>::value可以传递给模板,而现在我发现这个特性只关心它是否T t(T())是一个有效的表达式,它可能会调用T::T(const T&).现在假设这T是一个自定义类,那么我希望上面的模板行为如下:

  1. 如果我没有声明一个移动ctor,我希望该模板方法调用MoveAux<T,false>::doMove.
  2. 如果我宣布一个,我需要它来电话MoveAux<T,true>::doMove.

是否有可能使这项工作?

And*_*owl 21

是否std::is_move_constructible<T>::value == true暗示T有一个可用的移动构造函数?

移动构造函数或复制构造函数.请记住,复制结构的操作满足操作移动构造的所有要求,还有一些.

在标准术语中,MoveConstructible对象是对表达式求值的对象:

T u = rv; 
Run Code Online (Sandbox Code Playgroud)

使u相当于值rv施工前; 移动rv 的状态未指定.但由于它是不确定的,这意味着国家甚至可以等同于一个rv之前被移动:换句话说,u可能是复制rv.

事实上,该标准定义了CopyConstructible概念,是一个精致的的MoveConstructible概念(所以一切是CopyConstructible同样MoveConstructible的,但不是反之亦然).

如果是这样,它的默认行为是什么?

隐式生成的移动构造函数的行为是执行生成它的类型的数据成员的成员移动.

根据C++ 11标准的第12.8/15节:

非联合类的隐式定义的复制/移动构造函数X执行其基础和成员成员复制/移动.[注意:忽略非静态数据成员的大括号或大小写.另请参见12.6.2中的示例. - 尾注]

此外:

1 - f2移动构造?

是.

2 - 如果是这样,rval值不应该失效吗?

移动指针与复制指针相同.所以没有失效,也不应该继续.如果你想要一个移动构造函数,将移动的对象保留在特定的状态(即设置一个指针数据成员nullptr),你必须编写自己的 - 或者将这个职责委托给某些智能指针类,如std::unique_ptr.

请注意," 无效 " 这个词在这里并不完全正确.移动构造函数(以及移动赋值运算符)旨在使移动的对象保持有效(但未指定)状态.

换句话说,需要尊重类不变量 - 并且应该可以调用移动的对象操作,这些操作对其状态没有任何先决条件(通常是破坏和赋值).


bal*_*lki 7

移动构造函数的默认行为与复制构造函数相同,是否正确?如果这是真的

不,这是错误的。这仅适用于基元。它与复制构造函数类似。

默认生成的复制构造函数调用复制按照声明的顺序调用其所有成员的

但是默认生成的移动构造函数调用移动按照声明的顺序调用其所有成员的

现在下一个问题是,基元ints的复制/移动构造函数是什么floatpointer做什么的?

答案:他们只是复制值(复制和移动构造函数)


Nic*_*las 5

std :: is_move_constructible :: value == true表示T有一个可用的移动构造函数吗?

不.它声明您可以采用对象类型的右值表达式并从中构造对象.这是使用移动构造函数还是复制构造函数与此特征无关.

f2移动构建?

是.

如果是这样,rval值不应该失效吗?

不,这不是运动的运作方式.

我怎么知道一个类的实例是否可以正确移动构造(使旧的实例无效)?

这不是存在的"正确移动构造"的任何定义.如果你想"使旧的无效",那么你必须自己做.

移动建设通常可以保证没有任何关于旧的对象的状态.它将处于有效但未定义的状态.这种状态非常可以"与以前一样".移动指针的构造与复制指针相同.

如果你想在移动后"无效",那么你需要编写自己的移动构造函数,明确地这样做.

(我正在使用VS11)

那么你有没有编译器生成move构造函数在所有.并不重要,因为指针的移动和复制构造函数都做同样的事情.