c++ - 值传递和 std::move 与转发引用

标签 c++ pass-by-value forwarding-reference pass-by-const-reference pass-by-rvalue-reference

我经常遇到按值传递和移动的习惯用法:

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)。
    Test2 b(4.2f); // Invalid, but `std::is_constructible_v<Test2, float>` is (falsely) true.
    
    会在构造函数内部产生错误,而不是在调用站点产生错误(因此错误消息不太清楚,并且 SFINAE 不可能)。
  • 对于构造函数,它可以优先于复制构造函数(对于非常量左值)
    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/

相关文章:

c++ - 如何将c++程序编译成共享库以导入Python?

c++ - 如何将箭头::数组转换为标准:: vector ?

c# - 无法修改返回值,因为它不是变量

c++ - 结构化绑定(bind)和转发引用混合得好吗?

c++ - 如何通过通用引用或 std::forward 将这三个 C++ 模板函数合并为一个?

c++ - Boost Type Erasure的实践与发现

c++ - Visual Studio 2008 上 uint32_t 的奇怪 std::vector 问题

c++ - 为什么要将对象的拷贝作为函数的参数?为什么 const ref 不是参数的默认方式?

java - 当 Java ArrayList 作为参数传递给返回 void 的函数并在函数中修改时,如何修改?可能会对按值传递感到困惑

c++ - 无法从通用引用中捕获 lambda 中的引用?