转发参考文献的理由

问题描述 投票:0回答:1

最近,我在阅读有关转发参考文献的内容,偶然发现了这个常见的示例:


void put(const Data& data) { m_data = data; }

void put(Data&& data) {m_data = std::move(data);}

解决这个问题的方法是引入转发引用,如下所示:

template <class T>

void put(T&& data) {m_data = std::forward<T>(data);}  

但是,我注意到还有另一种解决方案,它的工作原理似乎相同,但稍微干净一些:


void put(Data data) {m_data = std::move(data);}  

这样,如果

put
要接收一些左值,则只会调用一个副本,如果它要接收右值,则只会调用移动操作。这与通用参考相同。

这也使用了更少的模板,并导致更容易出现编译错误。

鉴于此解决方案,转发引用的理由是什么 - 它可以提供简单的按值传递和移动习惯用法无法提供的功能?

谢谢!

c++ forwarding-reference
1个回答
0
投票

转发的大部分目的是尽可能长时间地维护对原始对象的引用,并且仅在真正必要时在最后一刻才转换到目标。

您建议的替代方案是尽早转换为目标类型,然后根据情况移动目标类型以防止其导致问题。有时这可能会奏效。但其他人则不会。一种明显的情况是,您可以直接从源类型分配到目标类型,但根本无法移动目标类型:

#include <utility>

class Foo {
    char const *m_data;
public:
    Foo &operator=(char const *data) { m_data = data; return *this; }
    Foo() {}
    Foo(Foo const &) = delete;
    Foo(Foo &&) = delete;
};

class Bar {
    Foo m_data;
public:
    template <class T>
    void put(T &&origin) { m_data = std::forward<T>(origin); }

    // void put2(Foo data) { m_data = data; }
};

int main() { 
    Bar b;
    b.put("Some string");
}

在这里,如果我们取消注释

Bar::put2
(使用您的技术),代码将不再编译,因为它依赖于
Foo
允许移动(或复制),但事实并非如此。

© www.soinside.com 2019 - 2024. All rights reserved.