【问题标题】:`X::X(const X&&)` Const Move Constructor? [duplicate]`X::X(const X&&)` 常量移动构造函数? [复制]
【发布时间】:2012-12-31 10:56:33
【问题描述】:

可能重复:
Move constructor signature

struct X
{
    X(X&);         // (1)
    X(X&&);        // (2)
    X(const X&);   // (3)
    X(const X&&);  // (4)
};

在重载决议中是否会选择(4)

【问题讨论】:

标签: c++ c++11


【解决方案1】:

是的。一种情况是当你有一个返回值const 的函数时:

const X f();

X x(f());

【讨论】:

  • 你的答案是正确的——但是 const 返回值没有意义,对吧?是否曾经使用过将返回值设为 const?
  • 不,这没有多大意义。有些人习惯这样做是为了避免像 C++03 中的 f() = x 这样无意义的事情,但现在这种习惯必须消失,因为它抑制了移动语义。
  • @R.MartinhoFernandes 我相信在某些情况下它确实有意义。如果你有时间,请检查我的答案和它下面的cmets,如果我错了,请纠正我。提前谢谢你。
  • 在某些情况下它是有意义的,例如当重载+ 时,你不想允许x + y = z
  • @K-ballo 但你想让foo(x+y) 移动,不是吗?
【解决方案2】:

另一种情况是当您将std::move 应用于const 对象时,如下例所示:

#include <iostream>

using namespace std;

struct X
{
    X() { cout << "default" << endl; }
    X(X&) { cout << "non const copy" << endl; }    // (1)
    X(X&&) { cout << "non const move" << endl; }   // (2)
    X(const X&) { cout << "const copy" << endl; }  // (3)
    X(const X&&){ cout << "const move" << endl; }  // (4)
};

void f(X const x)
{
}

int main()
{
    X const x;
    f(std::move(x));

    return 0;
}

上一个答案(X const f())中提到的情况可能不太常见,因为移动构造函数在执行 RVO 时大部分时间都被编译器省略(即使构造函数有副作用也可以这样做) .

const 对象移动到另一个const 对象中作为逻辑操作 确实有意义,如果您没有定义const 移动构造函数,那么您将不能去做。搬家只是转移所有权,所以在我看来,作为一种合乎逻辑的操作,它应该得到支持。

虽然从高层的角度来看,您不应该修改const 对象,并且确实移动对象需要修改它(在大多数情况下),但众所周知的类似情况是可以的修改const 对象“在幕后”,以实现更高级别的概念操作。例如,需要锁定非常量成员互斥体的 const 成员函数:您可以将互斥体变量声明为 mutable 以将其视为非常量对象。

因此,即使在这种情况下,我也将其视为 const 移动构造函数中的合法操作(只要需要),以修改移动对象的 mutable 成员(可能需要一些布尔标志由对象的析构函数)。请注意,如果您从上面的代码中删除 const 构造函数 (3) 和 (4),它将无法编译。如果只删除 (4),将选择复制构造函数 (3) - 这意味着您将无法移动 const 对象。

【讨论】:

  • 您似乎在暗示 const 移动构造函数应该 const_cast 摆脱 const 性,然后进行正常移动。我认为这根本不正确。一个 const move 构造函数应该与复制构造函数完全相同。移动 const 对象是没有意义的。
  • 修改原始声明为const 的对象是未定义行为。因此,安全的 const move 构造函数在任何情况下都不会更改源。但是这样就和拷贝构造函数一样了,声明重载也没有意义。
  • @aschepler 抱歉,我认为这不是真的。 const 对象可能有mutable 成员可以const 移动构造函数修改。正如我在之前的评论中提到的,该模式与您想要在 const 函数中锁定成员互斥锁时的模式相同。
  • 具体例子(格式不好,不知道怎么改进):struct X { [...] X(const X&amp;&amp; other){ other.flag = false; cout &lt;&lt; "const move" &lt;&lt; endl; } mutable bool flag = true; };这段代码是合法的。
  • 这并不完全正确:您可以修改 const 对象的 mutable 值。这使得从一个恒定的来源移动成为可能。例如,我可以想象一个向量类(当然不是std::vector),其const 移动构造函数只是复制数据指针和大小计数器(以及其他必要的东西),并在移动对象中设置mutable 标志到false,这样该对象的析构函数就不会尝试释放内存。不会发生逐个元素的复制,也不会发生双重释放,因此这是const 向量的有效、安全和合法的移动。我错了吗?
猜你喜欢
  • 2015-06-16
  • 2015-10-13
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-11
  • 2012-10-01
  • 1970-01-01
相关资源
最近更新 更多