【问题标题】:Why is make_shared calling move constructor twice? How to avoid it?为什么 make_shared 调用移动构造函数两次?如何避免?
【发布时间】:2021-10-09 04:51:00
【问题描述】:

我查看了 Stack Overflow 上的相关问题,据我了解,main() 的第一行应该调用构造函数,第二行应该触发一次移动构造函数的调用(或移动构造函数时的复制构造函数被删除)。

#include <iostream>
#include <memory>
using namespace std;

class Node {
public:
    Node()  { cout << "Called contructor\n"; }
    ~Node() { cout << "Called destructor\n"; }
    Node(const Node& other)  { cout << "Called copy-contructor\n"; }
    Node(Node&& other) { cout << "Called move-constructor\n"; }
};


int main(){
    Node a = Node();
    make_shared<Node>(a);
    return 0;
}

但是我从上面的代码得到的结果是:

Called contructor
Called copy-contructor
Called move-constructor
Called destructor
Called destructor
Called destructor

在我看来是因为传参调用了拷贝构造函数,而make_shared的实现中调用了move构造函数,是吗?调用make_shared 时是否可以避免两次构造函数调用(例如使用指针的引用传递)?有什么方法可以通过总共调用一次构造函数来获得shared_ptr&lt;Node&gt;

我的编译器版本:

Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 12.0.5 (clang-1205.0.22.11)
Target: x86_64-apple-darwin20.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

代码是使用默认参数的编译器:g++ test.cpp

【问题讨论】:

  • @rawrex 通过在Node a = Node() 前后输出,看来该行只触发了一次构造函数调用。
  • Node(const Node&amp;&amp; other) -- 去掉const。一个 const 右值引用在这里对你没有任何好处,因为你实际上不能离开它。
  • 您使用的是哪种语言版本?由于强制复制省略,C++17 永远不会收到移动构造函数调用,我不希望您在任何启用了优化的编译器中看到这一点。我也不能reproduce this with gcc
  • a 是一个左值,默认情况下会调用复制构造函数。仅当使用std::move() 将参数强制转换为右值引用时,才会调用移动构造函数。试试:std::make_shared&lt;Node&gt;(std::move(a));。此外,Node(const Node&amp;&amp; other) 是定义移动构造函数的错误方法。使用Node(Node&amp;&amp; other)
  • Apple Clang 是一种奇怪而可怕的野兽。考虑使用更普通的编译器,例如实际的 gcc 或实际的 clang。

标签: c++ function pointers smart-pointers shared


【解决方案1】:

似乎只有在使用g++ test.cpp而默认语言版本低于c++11时才会出现结果。使用g++ -std=c++11 test.cpp编译时,输出为:

Called contructor
Called copy-contructor
Called destructor
Called destructor

遵守标准。

我认为一个可能的解释是,当编译器检测到c++语法时,并没有更改为相应的语言版本,而是使用某种“技巧”来规避编译器错误,但这不符合语言标准.

【讨论】:

    猜你喜欢
    • 2021-05-16
    • 1970-01-01
    • 2015-01-23
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多