为啥在使用静态 constexpr 成员构造时 std::make_shared 与 new 不同? [复制]

Posted

技术标签:

【中文标题】为啥在使用静态 constexpr 成员构造时 std::make_shared 与 new 不同? [复制]【英文标题】:Why std::make_shared different with new when construct with static constexpr member? [duplicate]为什么在使用静态 constexpr 成员构造时 std::make_shared 与 new 不同? [复制] 【发布时间】:2017-04-19 03:07:58 【问题描述】:
#include <iostream>
#include <vector>
#include <memory>

class Node
public:
    static constexpr int data_size = sizeof(int);
;

class View
public:
    View(int size)
    
;

class Header: public Node
public:
    void foo()
        std::shared_ptr<View> v = std::make_shared<View>(data_size);
    

    void bar()
        std::shared_ptr<View> v(new View(data_size));
    
    View bar1()
        return View(data_size);
    
    void bar2()
        View *v = new View(data_size);
    
    int bar3()
        return data_size;
    
;

int main() 

    Header *h = new Header();

    // This 1 lines below will produce the error
    h->foo();

    // These 4 lines are ok
    h->bar();
    h->bar1();
    h->bar2();
    h->bar3();

    return 0;

调用 foo() 时会出现以下错误:

/Applications/CLion.app/Contents/bin/cmake/bin/cmake --build /Users/everettjf/code/cpptest/cmake-build-debug --target all -- -j 8
Scanning dependencies of target cpptest
[ 50%] Building CXX object CMakeFiles/cpptest.dir/main.cpp.o
[100%] Linking CXX executable cpptest
Undefined symbols for architecture x86_64:
  "Node::data_size", referenced from:
      Header::foo() in main.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [cpptest] Error 1
make[1]: *** [CMakeFiles/cpptest.dir/all] Error 2
make: *** [all] Error 2

我用new初始化shared_ptr的时候没问题,但是我用make_shared的时候链接出错了。

为什么 std::make_shared 在使用静态 constexpr 成员构造时与 new 不同?

我的环境是带有 Clion 的 macOS,CMakeList.txt 是:

cmake_minimum_required(VERSION 3.6)
project(cpptest)
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES main.cpp)
add_executable(cpptest $SOURCE_FILES)

【问题讨论】:

foo 函数调用没有给出错误,我刚刚检查了cpp.sh/4r3ef 哦,不。为什么?我只是用 Xcode 创建了一个新项目。 (macOS > 命令行工具)。并将代码粘贴到 main.cpp 中。然后构建,出现错误。 @卡皮尔 见Undefined reference error for static constexpr member @cpplearner 谢谢,这几乎是同一个问题。在 Xcode 中,可以通过 static_cast 修复错误,如下代码:std::make_shared&lt;View&gt;(static_cast&lt;int&gt;(data_size)); @Kapil See here wandbox.org/permlink/y7yyLKD4x9YKLu5K ,如果我选择 c++11 或 c++14 ,则会发生错误。如果我选择 c++1z ,没有错误。 【参考方案1】:

为什么 new 有效..

std::shared_ptr<View> v(new View(data_size));

在上面的代码中(我的猜测是),编译器将 data_size 替换为值本身。所以它编译并运行良好。

为什么 std::make_shared() 失败..

std::shared_ptr<View> v = std::make_shared<View>(data_size);

std::make_shared 做了一些称为完美转发的事情。在上述情况下,它需要知道 Node::data_size 的地址。由于您尚未在任何地方定义它,因此链接器找不到符号并引发错误。

要解决这个问题,请在代码中定义符号 Node::data_size。

【讨论】:

为什么完美转发需要知道Node::data_size的地址,它只适用于两件事首先它应该是模板函数,其次它应用引用折叠规则 也许完美并不完美……

以上是关于为啥在使用静态 constexpr 成员构造时 std::make_shared 与 new 不同? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

对静态 constexpr 数据成员的未定义引用错误

一个类不能有自己的静态 constexpr 成员实例吗?

为啥 std::stringstream 在静态内联时不能默认构造?

如何初始化std :: vector的静态constexpr成员 在c ++ 11中?

为啥编译器无法确定构造函数实际上是 constexpr?

c++11:为啥静态 constexpr 的类内初始化不是定义?