kei*_*ith 10 c++ move-semantics perfect-forwarding c++11 c++14
考虑以下类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 error as std::move cannot be used on reference
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
这是一个问题,因为我希望T既是引用类型又是值类型.
Tar*_*ama 11
这些示例都没有使用通用引用(转发引用,因为它们现在被称为).
转发引用仅在类型推导的情况下形成,但T&&
在构造函数中foo1
并且foo2
不推导,因此它只是一个右值引用.
由于两者都是右值引用,因此您应该同时使用std::move
它们.
如果要使用转发引用,则应使构造函数具有推导出的模板参数:
template <typename T>
struct foo1
{
T t_;
template <typename U>
foo1(U&& u) :
t_{ std::forward<U>(u) }
{
}
};
template <typename T>
struct foo2
{
foo1<T> t_;
template <typename U>
foo2(U&& u) :
t_{ std::forward<U>(u) }
{
}
};
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您不应该使用std::move
in foo1
,因为客户端代码可以传递左值并使对象无声地失效:
std::vector<int> v {0,1,2};
foo1<std::vector<int>> foo = v;
std::cout << v[2]; //yay, undefined behaviour
Run Code Online (Sandbox Code Playgroud)
一种更简单的方法是按值并无条件地std::move
进入存储:
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::move(t) }
{
}
};
Run Code Online (Sandbox Code Playgroud)
对于完美的转发版本:
对于传递值和移动版本:
考虑这段代码需要具备的性能以及需要更改和维护的程度,并根据需要选择一个选项.
归档时间: |
|
查看次数: |
951 次 |
最近记录: |