在面向价值的 属性 setter 中使用 std::move() 有什么陷阱吗?
Are there any pitfalls to using std::move() in value-oriented property setter?
我遇到了 answer to how to write C++ getters/setters and the author implies that when it comes to value-oriented properties, the setters in the standard library use the std::move()
这样的...
class Foo
{
X x_;
public:
X x() const { return x_; }
void x(X x) { x_ = std::move(x); }
}
(代码直接取自上述答案)
...利用移动运算符(如果已指定),可能会提高性能。
这本身对我来说很有意义 - 当按值传递给方法时,值被复制一次,因此如果可以移动它们,则无需将它们第二次复制到 属性。但是,我对 C++ 的了解不足以确定这样做在所有情况下都是安全的。
按值传递参数是否总是进行深拷贝?还是取决于对象?考虑到 std::move()
据说“向编译器发出信号,我不在乎移动的对象会发生什么”,如果我打算保留原始对象,这可能会产生意想不到的副作用。
抱歉,如果这是一个众所周知的问题,我正在学习 C++,并且真的想深入了解这门语言。
是的。
如果您始终向该参数发送右值,则按值接收参数并移动是可以的。发送左值也可以,但会比通过 const ref 接收慢,尤其是在循环中。
为什么?好像不是复制而是复制然后移动,其中移动在性能方面是微不足道的。
假.
您假设复制赋值与复制构造函数一样慢,这是错误的。
考虑一下:
std::string str_target;
std::string long1 = "long_string_no_sso hello1234";
std::string long2 = "long_string_no_sso goobye123";
str_target = long1; // allocation to copy the buffer
str_target = long2; // no allocation, reuse space, simply copy bytes
这就是为什么对于setter函数,默认情况下,您应该默认通过const ref接收,并添加一个右值ref以优化右值:
class Foo
{
X x_;
public:
X x() const { return x_; }
// default setter, okay in most cases
void x(X const& x) { x_ = x; }
// optionally, define an overload that optimise for rvalues
void x(X&& x) noexcept { x_ = std::move(x); }
};
唯一不适用的地方是构造函数参数和其他接收器函数,因为它们总是构造并且没有缓冲区可以重用:
struct my_type {
// No buffer to reuse, this->_str is a totally new object
explicit my_type(std::string str) noexcept : _str{std::move(str)}
private:
std::string _str;
};
我遇到了std::move()
这样的...
class Foo
{
X x_;
public:
X x() const { return x_; }
void x(X x) { x_ = std::move(x); }
}
(代码直接取自上述答案)
...利用移动运算符(如果已指定),可能会提高性能。
这本身对我来说很有意义 - 当按值传递给方法时,值被复制一次,因此如果可以移动它们,则无需将它们第二次复制到 属性。但是,我对 C++ 的了解不足以确定这样做在所有情况下都是安全的。
按值传递参数是否总是进行深拷贝?还是取决于对象?考虑到 std::move()
据说“向编译器发出信号,我不在乎移动的对象会发生什么”,如果我打算保留原始对象,这可能会产生意想不到的副作用。
抱歉,如果这是一个众所周知的问题,我正在学习 C++,并且真的想深入了解这门语言。
是的。
如果您始终向该参数发送右值,则按值接收参数并移动是可以的。发送左值也可以,但会比通过 const ref 接收慢,尤其是在循环中。
为什么?好像不是复制而是复制然后移动,其中移动在性能方面是微不足道的。
假.
您假设复制赋值与复制构造函数一样慢,这是错误的。
考虑一下:
std::string str_target;
std::string long1 = "long_string_no_sso hello1234";
std::string long2 = "long_string_no_sso goobye123";
str_target = long1; // allocation to copy the buffer
str_target = long2; // no allocation, reuse space, simply copy bytes
这就是为什么对于setter函数,默认情况下,您应该默认通过const ref接收,并添加一个右值ref以优化右值:
class Foo
{
X x_;
public:
X x() const { return x_; }
// default setter, okay in most cases
void x(X const& x) { x_ = x; }
// optionally, define an overload that optimise for rvalues
void x(X&& x) noexcept { x_ = std::move(x); }
};
唯一不适用的地方是构造函数参数和其他接收器函数,因为它们总是构造并且没有缓冲区可以重用:
struct my_type {
// No buffer to reuse, this->_str is a totally new object
explicit my_type(std::string str) noexcept : _str{std::move(str)}
private:
std::string _str;
};