【发布时间】:2018-05-01 19:03:41
【问题描述】:
当类模板具有静态成员时,我们需要该成员的附加(模板化)定义。现在,该定义实际上并没有立即实例化,而是需要实例化封闭模板,并且需要“使用”静态字段。到目前为止一切顺利。
但是,我对 GCC / Linux 的行为令人惊讶。 (g++ 4.7 和 7.2)
#include <iostream>
using std::cout;
using std::endl;
template<typename T>
class Factory
{
public:
T val;
Factory()
: val{}
{
cout << "Factory-ctor val="<<val<<endl;
}
};
template<typename T>
class Front
{
public:
static Factory<T> fac;
Front()
{
cout << "Front-ctor val="<<fac.val<<endl;
fac.val += 100;
}
T&
operate ()
{
cout << "Front-operate val="<<fac.val<<endl;
++ fac.val;
return fac.val;
}
};
template<typename T>
Factory<T> Front<T>::fac;
namespace {
Front<int> front;
int global_int = front.operate();
}
int
main (int, char**)
{
Front<int> fint;
int& i = fint.operate();
cout << "main: val="<<i<<endl;
cout << "global_int.......="<<global_int<<endl;
return 0;
}
在匿名命名空间中,我们首先创建 Front 的静态实例,然后在其上调用 operate() 函数,该函数使用静态工厂成员。输出和值都清楚地表明静态成员的 ctor 在使用后被调用。这种行为背后的原因是什么?这对我来说似乎违反直觉:假设工厂管理一些资源,资源就会泄露。
~$ g++ --version
g++ (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0
~$ g++ --std=gnu++17 demo.cpp -o demo
~$ ./demo
Front-ctor val=0
Front-operate val=100
Factory-ctor val=0
Front-ctor val=0
Front-operate val=100
main: val=101
global_int.......=101
我也尝试过 Clang (3.5),这只是段错误。
PS:显而易见的解决方法是将工厂变成 Meyers Singleton。然而,我希望 ctors 和 dtors 系统在这种基本情况下是无懈可击的(请注意,我们不是指来自其他翻译单元的任何静态)。因此,我主要对解释该观察的推理感兴趣。
【问题讨论】: