我认为我对rvalue引用和move语义的理解有一些漏洞。
就我现在所理解的rvalue引用而言,我可以通过两种方式实现函数f,这样它就可以从移动语义中获益。
第一个版本:实现这两个版本
void f(const T& t);
void f(T&& t);这将导致相当多的冗余,因为这两个版本都有(几乎)相同的实现。
第二版:仅实现
void f(T t);调用f将导致调用T的副本或移动构造函数。
有个问题。这两个版本的比较如何?我怀疑:在第二个版本中,动态分配的数据的所有权可能被移动构造函数移动,而t中的非动态分配数据及其成员需要被复制。在第一个版本中,两个版本都没有分配任何额外的内存(除了引用后面的指针)。
如果这是正确的,我是否可以避免编写f的实现基本上两次,而没有第二个版本的缺点?
发布于 2022-10-08 20:52:24
如果需要接受T&&参数,这通常意味着要将对象移到某处并保留它。这类函数通常与const T&重载配对,因此它可以同时接受rvalue和lvalue。
在这种情况下,第二个版本(只有一个以T作为参数的重载)总是效率较低,但很可能不太有效。
对于第一个版本,如果传递一个lvalue,则函数接受一个引用,然后生成一个副本将其存储在某个地方。那是一份副本结构或任务。如果传递一个rvalue,则函数再次接受引用,然后移动对象来存储它。这是建筑或任务的一步。
对于第二个版本,如果您传递一个lvalue,它将被复制到参数中,然后函数可以移动它。如果您传递一个rvalue,如果被移动(假设该类型有一个move构造函数)到参数中,那么这个函数也可以移动它。在这两种情况下,这是比第一个版本多一个移动构造或分配。
还请注意,在某些情况下可以发生复制省略。
第二个版本的好处是您不需要多个重载。对于第一个版本,需要对需要复制或移动的n个参数进行2^n重载。
在只有一个参数的简单情况下,我有时会这样做以避免重复代码:
void f(const T& t) {
f_impl(t);
}
void f(T&& t) {
f_impl(std::move(t));
}
// this function is private or just inaccessible to the user
template<typename U>
void f_impl(U&& t) {
// use std::forward<U>(t)
}https://stackoverflow.com/questions/74000262
复制相似问题