【问题标题】:No constructor called when calling function调用函数时没有调用构造函数
【发布时间】:2018-05-30 01:05:08
【问题描述】:

MyType 定义了复制和移动 ctor。执行以下sn-p时(用VS2015编译后):

template<typename T>
void f(T&& o) {
    // do something with o
}

int main() {
    MyType o{ 1, 2, 3 };
    f(o); // call of copy-constructor expected
    f(std::move(o)); // call of move-constructor expected
}

我本来希望在第一次调用f 之后调用复制构造函数,并在第二次调用f 之后调用移动构造函数。但是在任何情况下实际上都没有调用构造函数。我怀疑这种行为是编译器优化,但不确定可移植性或是否符合标准。

【问题讨论】:

  • 您希望MyType&amp; r = o 调用复制构造函数吗?
  • @Barry:不,当然不是。我错过了 T&& 在模板中被推断为 T& 的观点。但是关于第二次调用f(std::move(o)),我仍然不知道 f 中的对象如何引用另一个在调用站点被移动的对象。
  • 如果不是通过调用 move ctor(我实际定义的,请参阅我的问题),那么这个临时对象究竟是如何构造的?
  • @Angle.Bracket 要检查某些东西是否是编译器优化,您可以使用编译器资源管理器而不定义要检查的函数。如果编译器看不到实现,则无法优化。例如 godbolt.org/g/dp9wao 您不必完全理解程序集。只需查看call 语句即可了解其名称。

标签: c++ c++11 c++14 move-semantics perfect-forwarding


【解决方案1】:

这两个调用都是通过引用进行的——第一个是 lvalue 引用,第二个是 rvalue 引用。 T&amp;&amp; 两者都可以使用,称为forward reference (N4164)。 Scott Meyers 称它们为 universal references,作为模板参数和 auto&amp;&amp; 特别有用。

std::move 用于指示所有权转移,但实际上不做任何动作。它的效果是静态转换到右值引用。

所以你有:

void f(MyType& ) {}
void f(MyType&& ) {}
...
f(o);                         // calls void f(MyType& )
f(static_cast<MyType&&>(o));  // calls void f(MyType&& )

通常在初始化对象时调用移动构造函数。

Move constructorscppreference.com

只要被重载选中,就会调用移动构造函数 分辨率,这通常发生在对象初始化时(通过 从右值(xvalue 或 prvalue) (C++17 前)xvalue (C++17 起) 相同类型,包括

  • 初始化:T a = std::move(b);T a(std::move(b));,其中b是T类型;

  • 函数参数传递:f(std::move(a));,其中 a 是 T 类型,f 是 void f(T t);

  • 函数返回:return a; 在函数内,例如 T f(),其中 a 是具有移动构造函数的 T 类型。

如果您将f 更改为void f(T o),第一次调用将调用复制构造函数,第二次调用将调用移动构造函数。


Universal vs Forwarding References in C++

【讨论】:

  • 术语为转发引用。
  • 或者更确切地说是forwarding reference(注意3.1:Q&A/为什么不是通用参考)。
  • 在第一种情况下,我看到 o in f 引用了 main 中的 o。但是,当 main 中的参数现在被移出时,第二种情况下的 o 引用是什么?
  • 您的模板在使用ostd::move(o) 调用时会生成这两个函数。 o 绑定到 T& 和 move(o) 到 T&& - 两个引用。没有新对象没有调用构造函数。没有任何东西被移动。
  • en.cppreference.com/w/cpp/language/move_constructor - "函数参数传递:f(std::move(a));,其中a是T类型,f是void f(T t); " -- T 按值,需要初始化
猜你喜欢
  • 2021-09-09
  • 2017-02-08
  • 2013-05-26
  • 1970-01-01
  • 2016-07-12
  • 2017-01-01
  • 1970-01-01
  • 2015-09-21
  • 1970-01-01
相关资源
最近更新 更多