由于我们在C++中移动了语义,所以现在通常这样做
void set_a(A a) { _a = std::move(a); }
Run Code Online (Sandbox Code Playgroud)
原因是,如果a是左值,则副本将被删除,并且只有一个移动.
但如果a是左值,会发生什么?似乎将有一个复制结构,然后是一个移动赋值(假设A有一个适当的移动赋值运算符).如果对象具有太多成员变量,则移动分配可能成本很高.
另一方面,如果我们这样做
void set_a(const A& a) { _a = a; }
Run Code Online (Sandbox Code Playgroud)
只有一个副本分配.如果我们传递左值,我们可以说这种方式优于传值的习语吗?
让我们考虑一个对象foo(可能是一个int,一个double,一个习惯struct,一个class,等等).我的理解是,通过foo引用函数(或只是传递指针foo)来传递更高的性能,因为我们避免制作本地副本(如果foo很大则可能很昂贵).
但是,从这里的答案来看,似乎64位系统上的指针实际上可以预期大小为8字节,无论指向什么.在我的系统上,a float是4个字节.这是否意味着如果foo是类型float,那么仅通过值传递而不是给它指向它是更有效的foo(假设没有其他约束可以使得使用一个比函数内的另一个更有效)?
c++ pointers pass-by-reference pass-by-value pass-by-pointer
我已经看到它说一个operator=带有相同类型by-value的参数的文件在C++ 11中既作为复制赋值运算符又作为移动赋值运算符:
Foo& operator=(Foo f)
{
swap(f);
return *this;
}
Run Code Online (Sandbox Code Playgroud)
替代方案的重复次数将超过两倍,并且可能出现错误:
Foo& operator=(const Foo& f)
{
Foo f2(f);
swap(f2);
return *this;
}
Foo& operator=(Foo&& f)
{
Foo f2(std::move(f));
swap(f2);
return *this;
}
Run Code Online (Sandbox Code Playgroud)
在什么情况下,ref-to-const和r-value重载优先通过值,或何时需要?我正在考虑std::vector::push_back,例如,它被定义为两个重载:
void push_back (const value_type& val);
void push_back (value_type&& val);
Run Code Online (Sandbox Code Playgroud)
在第一个示例中,pass by value 用作复制赋值运算符和移动赋值运算符,无法push_back在Standard中定义为单个函数?
void push_back (value_type val);
Run Code Online (Sandbox Code Playgroud) 想象一下,你有很多重载的方法(在C++ 11之前)看起来像这样:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
};
Run Code Online (Sandbox Code Playgroud)
这个函数复制了a(MyBigType),所以我想通过提供一个版本f来移动a而不是复制它来添加优化.
我的问题是,现在f重载次数将重复:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
void f(MyBigType&& a, int id);
void f(MyBigType&& a, string …Run Code Online (Sandbox Code Playgroud) 考虑以下类foo1和foo2
template <typename T>
struct foo1
{
T t_;
foo1(T&& t) :
t_{ std::move(t) }
{
}
};
template <typename T>
struct foo2
{
foo1<T> t_;
foo2(T&& t) :
t_{ std::forward<T>(t) }
{
}
};
Run Code Online (Sandbox Code Playgroud)
始终是构造函数foo1表示初始化成员变量的正确方法T吗?即通过使用std::move.
总是这样的构造函数foo2表示foo1<T>由于需要转发到foo1的构造函数而初始化成员变量的正确方法吗?即通过使用std::forward.
更新
以下示例无法foo1使用std::move:
template <typename T>
foo1<T> make_foo1(T&& t)
{
return{ std::forward<T>(t) };
}
struct bah {};
int main()
{
bah b;
make_foo1(b); // compiler …Run Code Online (Sandbox Code Playgroud) 例如:
void f(T&& t); // probably making a copy of t
void g()
{
T t;
// do something with t
f(std::move(t));
// probably something else not using "t"
}
Run Code Online (Sandbox Code Playgroud)
void f(T const& t)在这种情况下是等效的,因为任何好的编译器都会产生相同的代码?如果这很重要,我对> = VC10和> = GCC 4.6感兴趣.
编辑:
根据答案,我想详细说明一下这个问题:
比较rvalue-reference和pass-by-value方法,它是很容易忘记用std::move在pass-by-value.编译器是否仍然可以检查是否不再对变量进行更改并消除不必要的副本?
rvalue-reference例如f(T()),方法仅使优化版本"隐式",并且要求用户明确指定其他情况,如果用户未完成实例f(std::move(t)),则明确地制作副本.那么,在这种优化相关的光中,方法被认为是好的吗?f(T(t));trvalue-reference
我认为具有通用引用参数的构造函数比没有引用的构造函数具有更好的性能。
From cppreference (https://en.cppreference.com/w/cpp/utility/functional/function/function), we can see that the template constructor for std::function is not using reference.
template< class F > function( F f );
Run Code Online (Sandbox Code Playgroud)
Is it a mistake? If not, why the standard doesn't requires the constructor use universal reference?
EDIT:
Let's think about two cases.
Using universal reference:
lvalue case: 4 bytes are copied.
rvalue case: 4 bytes are copied. (Will you …