我想知道是否允许编译器在以下setter方法中自动使用wstring的move构造函数(没有显式调用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不会改变程序行为。
禁止移动,是否会应用其他类型的复制省略?
答案 0 :(得分: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中使用。并且他可能不会被允许在未来的标准中,因为这个功能在编译器中很难实现,并且只是为用户带来方便。
答案 1 :(得分:1)
不,这里不会使用移动语义,因为str可以在下一个代码中使用,实际上即使它是rvalue你仍然需要std :: move强制它..如果你想使用移动语义我会建议获得wstring&amp;&amp; str到函数然后使用move ..
答案 2 :(得分:1)
不,不允许使用编译器。由于某些原因,不仅因为很难做到。我认为复制和移动可能会产生副作用,你需要知道什么时候可以使用它们。例如,众所周知,返回一个本地对象会移动它 - 你希望它记录在案,是可以的。
因此,我们有以下可能性:
你的例子:
void SetString(std::wstring str)
{
m_str = str;
}
对于r值:str
中的一个r-ref,加上m_str
的副本。对于l值:str
中的副本和m_str
中的副本。
我们可以手动“更好”地做到这一点:
void SetString( std::wstring str)
{
m_str = std::move(str);
}
对于r值:str
中的一个r-ref,再加上m_str
。对于l值:str
中的副本和m_str
中的移动。
如果出于某种原因(你希望它在没有C ++ 11的情况下进行编译而不进行更改,但在移植代码时自动利用C ++ 11?)您不希望“手动优化”您可以执行的代码:
void SetString(const std::wstring& str)
{
m_str = str;
}
对于r值:str
中的一个参考,以及m_str
的副本。对于l值:str
中的引用和m_str
中的副本。永远不要2份。