【问题标题】:How does c++ choose move and copy constructc++如何选择移动和复制构造
【发布时间】:2021-07-04 11:31:55
【问题描述】:

我正在自己编写“任何”课程。如下代码所示,我有两个问题。

#include <assert.h>
#include <iostream>
#include <typeinfo>

class Test{};

class Any {
 public:
  template<typename DataType>
  explicit Any(DataType&& in) {
    Test t;
    std::cout
        << typeid(t).name() << "  "
        << typeid(in).name() << "  "
        << typeid(Test()).name();
    std::cout << " move";
  }
  template<typename DataType>
  explicit Any(const DataType& in) {
    Test t;
    std::cout
        << typeid(t).name() << "  "
        << typeid(in).name() << "  "
        << typeid(Test()).name();
    std::cout << " copy";
  }
};

int main()
{
  Test t;
  Any a(t);
}

编译命令是

g++ main.cpp -std=c++11

输出是

4Test  4Test  F4TestvE move
  1. 为什么 c++ 选择移动构造而不是复制构造? "t" 是 Test 的一个实例,它不是右值。
  2. 为什么 typeid(in) 和 typeid(Test()) 不一样?它们都是右值。

非常感谢。

【问题讨论】:

  • 第一个构造函数有一个“通用引用”(查找它)作为参数,因此它可以接受任何值类别,而您不需要另一个。请注意,这些不是复制/移动构造函数,因为参数类型不是对 Any 本身的引用。

标签: c++ copy-constructor move-constructor typeid typeinfo


【解决方案1】:
  1. 为什么 c++ 选择移动构造而不是复制构造? "t" 是 Test 的一个实例,它不是右值。

第一个构造函数重载采用forwarding reference 并且可以接受左值和右值。 (因此它不是移动构造函数。)对于Any a(t);,它是完全匹配的,而对于第二次重载,t 需要转换为const

  1. 为什么 typeid(in) 和 typeid(Test()) 不一样?它们都是右值。

Test() 是一个函数类型,它返回Test 并且不接受任何内容,因此typeid(Test()) 给出不同的结果。

【讨论】:

    【解决方案2】:

    调用移动变体的原因是它的签名实际上不需要传递右值引用。

    如果U = T const&amp;U&amp;&amp; 将是T const&amp;,而不是T&amp;&amp;。在您的情况下,DataType 绑定到 Test&amp;,而不是像您预期的那样绑定到 Test&amp;&amp; 因此崩溃并且什么都不做。如果您添加一个 static_assert(std::is_same_v&lt;DataType, Test&amp;&gt;);,您可以看到这一点。
    如果您将模板替换为固定类型,即Test&amp;&amp; 而不是DataType&amp;&amp;,则会调用您的函数。

    查看reference,参考部分正在折叠。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      • 2018-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-01
      • 2023-03-28
      相关资源
      最近更新 更多