【问题标题】:What is point of passing rvalue reference to class constructor?将右值引用传递给类构造函数有什么意义?
【发布时间】:2020-04-28 19:46:14
【问题描述】:

好的

所以我有一个班级,MyClass。我想用一个整数向量来构造这个类。我想将此向量移动到对象中。该类未模板化。

class Myclass {
     public:
     Myclass (std::vector<int> && in) : vec{in} {};
     Myclass (std::vector<int> & in) : vec{in} {};

    private:
    std::vector<int> vec;
    }

我主要有

std::vector<int> orig (100);
Myclass A {orig};
std::cout << A.size() << '\n';

我希望将“orig”移入“A”后为空。在上述任何一个选项中都不会发生这种情况。 即使我这样做了

    std::vector<int> orig (100);
    Myclass A {std::move(orig)};
    std::cout << A.size() << '\n';  // still prints 100

看来我可以通过

 Myclass (std::vector<int> && in) : vec{std::move(in)} {};   // (1)

 Myclass (std::vector<int> & in) : vec{std::move(in)} {};    // (2)

Myclass (std::vector<int> && in) : vec{std::forward<std::vector<int>(in)} {};    // (3)

我的问题是为什么 (1) 的行为与 (2) 完全一样?

【问题讨论】:

  • 请注意,您可以将两个构造函数统一为一个 Myclass(std::vector&lt;int&gt; in) : vec{std::move(in)} { } 构造函数。调用者可以根据是否需要保留副本来决定是移动构造还是复制构造临时向量。

标签: c++ constructor move-semantics rvalue


【解决方案1】:

关于引用,右值和左值,要记住的是它们是左值。这意味着,如果您有对某事物的引用,则该引用是一个左值,您需要 std::move 将其转换为右值,以便可以移动它。

Myclass (std::vector&lt;int&gt; &amp;&amp; in)Myclass (std::vector&lt;int&gt; &amp; in) 之间的真正区别在于你必须使用第一个

Myclass A {std::move(orig)};
// or
Myclass A {std::vector(100)};

并且不能将左值传递给它,而与 second 一样,您只能使用

Myclass A {orig};

因为它不会让您将右值传递给它。


还要注意构造函数 3 是“不正确的”。当您有转发参考时,您应该只使用std::forwardstd::vector&lt;int&gt; &amp;&amp; in 是右值引用,而不是转发引用,因此您应该改用 std::move。要正确使用 forward,您需要一个模板构造函数,例如

template <typename T, std::enable_if_t<
                                       std::is_same<std::decay_t<T>, 
                                       std::vector<int>>, bool> = true>
Myclass (T&& in) : vec{std::forward<T>(in)} {}; 

【讨论】:

  • 非常感谢您的回答。我只看到了带有模板的前锋,这就是为什么我明确提到我的课程没有模板化......虽然它似乎“工作”但也许它没有。您的第二个示例,即时制作矢量并将其传递给构造函数是拥有右值引用版本的一个很好的理由。我没想到!我试图思考如果它实际上没有“转发”右值引用,为什么它可能有用。
  • @TCD 在这种情况下它会“工作”,但这是更令人高兴的巧合。仅仅将类作为模板是不够的。如果您有 template &lt;typename T&gt; struct foo{ foo(T&amp;&amp;); }; 那个 foo(T&amp;&amp;)不是转发引用,它是一个右值引用。 只有当您有类似 /*template &lt;typename T&gt;*/ struct foo{ template &lt;typename T&gt; foo(T&amp;&amp;); }; 的信息时,您才会获得转发参考
猜你喜欢
  • 1970-01-01
  • 2018-02-25
  • 2018-01-20
  • 2016-09-01
  • 1970-01-01
  • 2018-05-09
  • 1970-01-01
  • 2012-06-06
  • 1970-01-01
相关资源
最近更新 更多