我经常遇到按值传递和移动的习惯用法:
struct Test
{
Test(std::string str_) : str{std::move(str_)} {}
std::string str;
};
但在我看来,在某些情况下传递常量引用或右值引用可以保存拷贝。像这样的东西:
struct Test1
{
Test1(std::string&& str_) : str{std::move(str_)} {}
Test1(std::string const& str_) : str{str_} {}
std::string str;
};
或者也许使用转发引用来避免编写两个构造函数。像这样的东西:
struct Test2
{
template<typename T> Test2(T&& str_) : str{std::forward<T>(str_)} {}
std::string str;
};
是这样的吗?如果是这样,为什么不使用它呢?
此外,C++20 似乎允许使用自动参数来简化语法。我不确定这种情况下的语法是什么。考虑:
struct Test3
{
Test3(auto&& str_) : str{std::forward<decltype(str_)>(str_)} {}
std::string str;
};
struct Test4
{
Test4(auto str_) : str{std::forward<decltype(str_)>(str_)} {}
std::string str;
};
编辑:
建议的问题内容丰富,但没有提及“自动”情况。
最佳答案
But it seems to me that passing by either const reference or rvalue reference can save a copy in some situations.
确实如此,但它需要更多的重载(如果有多个参数,情况甚至更糟)。
按值传递和移动惯用语(在最坏的情况下)有一个额外的移动。大多数时候这是一个很好的权衡。
maybe using a forwarding reference to avoid writing both constructors.
转发引用有其自身的陷阱:
- 不允许参数使用
{..}
语法,因为{..}
没有类型。
这是不可能的。Test2 a({5u, '*'}); // "*****"
- 不限于有效类型(需要额外的
requires
或SFINAE)。
会在构造函数内部产生错误,而不是在调用站点产生错误(因此错误消息不太清楚,并且 SFINAE 不可能)。Test2 b(4.2f); // Invalid, but `std::is_constructible_v<Test2, float>` is (falsely) true.
- 对于构造函数,它可以优先于复制构造函数(对于非常量左值)
会产生错误,因为Test2 c(a); // Call Test2(T&&) with T=Test2& // instead of copy constructor Test2(const Test2&)
std::string
无法从Test2&
构造。
关于c++ - 值传递和 std::move 与转发引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69742511/