为啥在使用静态 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<View>(static_cast<int>(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 不同? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
为啥 std::stringstream 在静态内联时不能默认构造?