4

我想知道是否允许编译器在以下 setter 方法中自动使用 wstring 的移动构造函数(无需显式调用 std::move):

void SetString(std::wstring str)
{
    m_str = str;  // Will str be moved into m_str automatically or is std::move(str) needed?
}

从我读过的内容来看,似乎不允许编译器做出这个决定,因为 str 是一个左值,但很明显在这里使用 move 不会改变程序行为。

除非移动,是否会应用其他类型的复制省略?

4

3 回答 3

3

[是] 编译器 [...] 允许自动使用移动构造函数

是的,那会很好。但这不仅是一种优化,而且对语言有真正的影响。

考虑一个只移动类型,如unique_ptr

std::unique_ptr<int> f()
{
  std::unique_ptr<int> up;
  return up; // this is ok although unique_ptr is non-copyable.
}

假设您的规则将包含在 C++ 标准中,称为“参数最后出现”的规则。

void SetString(std::unique_ptr<int> data)
{
    m_data = data; // this must be ok because this is "argument's last occurence"
}

检查返回中是否使用了标识符很容易。检查它是否是“参数的最后一次出现”不是。

void SetString(std::unique_ptr<int> data)
{
    if (condition) {
      m_data = data; // this is argument's last occurence
    } else {
      data.foo();
      m_data = data; // this is argument's last occurence too
    }
    // many lines of code without access to data
}

这也是有效的代码。所以每个编译器都需要检查“参数的最后一次出现”,这不是一件容易的事。为此,他必须扫描整个函数以确定第一行是否有效。如果您必须向下滚动 2 页来检查这一点,作为人类也很难推理。

不,编译器不允许在 C++11 中使用。而且他可能不会在未来的标准中被允许,因为这个特性通常很难在编译器中实现,它只是为用户提供方便。

于 2013-03-21T19:13:12.110 回答
1

不,这里不会使用移动语义,因为 str 可以在下一个代码中使用,事实上即使它是右值你仍然必须 std::move 强制它..如果你想使用移动语义,我建议你得到wstring&& str 到函数,然后使用 move..

于 2013-03-21T18:41:28.513 回答
1

不,不允许编译器。由于一些原因,不仅仅是因为它很难做到。我认为复制和移动可能会产生副作用,您需要知道何时可以使用它们。例如,众所周知,返回一个本地对象会移动它——你期望,它被记录在案,是可以的。

所以,我们有以下几种可能:

你的例子:

void SetString(std::wstring str)
{
     m_str = str;  
}

对于 r-values:一个 r-ref in str,加上一个 into 的副本m_str。对于 l 值: 中的副本 中str的副本m_str

我们可以手动“做得更好”:

void SetString( std::wstring str)
{
     m_str = std::move(str);  
}

对于 r 值:一个 r-ref in str,加上一个 move into m_str。对于 l 值:stra move in 中的副本m_str

如果出于某种原因(您希望它在不更改 C++11 的情况下编译,但在移植代码时自动利用 C++11?)您不希望“手动优化”您可以执行的代码:

void SetString(const std::wstring& str)
{
     m_str = str;  
}

对于 r 值:一个参考 in str,加上一个副本 into m_str。对于 l 值: 中str的副本中的引用m_str。从不 2 副本。

于 2013-03-21T19:14:46.010 回答