make_shared 对已初始化静态成员变量的未定义引用
Undefined reference to initialized static member variable with make_shared
使用-std=c++14编译以下代码:
#include <memory>
class A
{
public:
static constexpr int c = 0;
std::shared_ptr<int> b;
A() {
b = std::make_shared<int> (c);
}
};
int main () {
A a;
return 0;
}
给出链接器错误“对 `A::c' 的未定义引用”,而在不是“make_shared”的其他上下文中使用“A::c”时,不会发生此错误。特别是,以下代码可以正确编译和工作:
class A
{
public:
static constexpr int c = 0;
std::shared_ptr<int> b;
A() {
int cc = c;
b = std::make_shared<int> (cc);
}
};
从 C++17 开始,第一个代码应该可以正常工作:static constexpr
class 成员变量是隐式的 inline
,这意味着编译器负责确保定义存在。
在 C++17 之前,由于 ODR 违规,代码具有未定义的行为(不需要诊断)。 odr-used 的静态 class 成员还必须具有外联定义。
将引用绑定到变量算作 odr-use,make_shared<int>(c)
会发生这种情况,因为该函数定义为:
template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );
因此参数绑定到引用参数。
理论上你应该可以使用 make_shared<int>(+c)
解决它...然后引用绑定到 +c
的临时结果而不是 c
本身,因此没有 ODR 使用。与您在问题中发布的解决方法类似的理论。
enum { c = 0 };
是另一种可能的解决方法,如果实际代码中的类型是 int
.
使用-std=c++14编译以下代码:
#include <memory>
class A
{
public:
static constexpr int c = 0;
std::shared_ptr<int> b;
A() {
b = std::make_shared<int> (c);
}
};
int main () {
A a;
return 0;
}
给出链接器错误“对 `A::c' 的未定义引用”,而在不是“make_shared”的其他上下文中使用“A::c”时,不会发生此错误。特别是,以下代码可以正确编译和工作:
class A
{
public:
static constexpr int c = 0;
std::shared_ptr<int> b;
A() {
int cc = c;
b = std::make_shared<int> (cc);
}
};
从 C++17 开始,第一个代码应该可以正常工作:static constexpr
class 成员变量是隐式的 inline
,这意味着编译器负责确保定义存在。
在 C++17 之前,由于 ODR 违规,代码具有未定义的行为(不需要诊断)。 odr-used 的静态 class 成员还必须具有外联定义。
将引用绑定到变量算作 odr-use,make_shared<int>(c)
会发生这种情况,因为该函数定义为:
template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );
因此参数绑定到引用参数。
理论上你应该可以使用 make_shared<int>(+c)
解决它...然后引用绑定到 +c
的临时结果而不是 c
本身,因此没有 ODR 使用。与您在问题中发布的解决方法类似的理论。
enum { c = 0 };
是另一种可能的解决方法,如果实际代码中的类型是 int
.