- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
在尝试使用 Clang 编译现有(GCC 开发的)代码库时,我们遇到了这个有趣的问题。结果,Clang 编译的可执行文件创建了一些单例的多个实例。不确定我们的使用和理解是否符合标准,或者Linux上的GCC和/或Clang或C++标准库和工具链是否真的有问题。
以下是摘录,省略了任何锁定、生命周期问题、初始化和清理
文件-1:clang-static-init.hpp
#include <iostream>
using std::cout;
namespace test {
/* === Layer-1: a singleton factory based on a templated static variable === */
template<typename I ///< Interface of the product type
,template <class> class Fac ///< Policy: actual factory to create the instance
>
struct Holder
{
static I* instance;
I&
get()
{
if (!instance)
{
cout << "Singleton Factory: invoke Fabrication ---> address of static instance variable: "<<&instance<<"...\n";
instance = Fac<I>::create();
}
return *instance;
}
};
/**
* allocate storage for the per-type shared
* (static) variable to hold the singleton instance
*/
template<typename I
,template <class> class F
>
I* Holder<I,F>::instance;
template<typename C>
struct Factory
{
static C*
create()
{
return new C();
}
};
/* === Layer-2: configurable product type === */
template<typename I>
struct Adapter
{
typedef I* FactoryFunction (void);
static FactoryFunction* factoryFunction;
template<typename C>
static I*
concreteFactoryFunction()
{
return static_cast<I*> (Factory<C>::create());
}
template<typename X>
struct AdaptedConfigurableFactory
{
static X*
create()
{
return (*factoryFunction)();
}
};
};
/** storage for the per-type shared function pointer to the concrete factory */
template<typename I>
typename Adapter<I>::FactoryFunction* Adapter<I>::factoryFunction;
template<typename C>
struct TypeInfo { };
/**
* Singleton factory with the ability to configure the actual product type C
* only at the \em definition site. Users get to see only the interface type T
*/
template<typename T>
struct ConfigurableHolder
: Holder<T, Adapter<T>::template AdaptedConfigurableFactory>
{
/** define the actual product type */
template<typename C>
ConfigurableHolder (TypeInfo<C>)
{
Adapter<T>::factoryFunction = &Adapter<T>::template concreteFactoryFunction<C>;
}
};
/* === Actual usage: Test case fabricating Subject instances === */
struct Subject
{
static int creationCount;
Subject();
};
typedef ConfigurableHolder<Subject> AccessPoint;
/** singleton factory instance */
extern AccessPoint fab;
Subject& fabricate();
} // namespace test
文件 2:clang-static-init-1.cpp
#include "clang-static-init.hpp"
test::Subject&
localFunction()
{
return test::fab.get();
}
int
main (int, char**)
{
cout << "\nStart Testcase: invoking two instances of the configurable singleton factory...\n\n";
test::Subject& ref1 = test::fab.get();
test::Subject& sub2 = test::fabricate(); ///NOTE: invoking get() from within another compilation unit reveales the problem
test::Subject& sub3 = localFunction();
cout << "sub1=" << &ref1
<< "\nsub2="<< &sub2
<< "\nsub3="<< &sub3
<< "\n";
return 0;
}
文件 3:clang-static-init-2.cpp
#include "clang-static-init.hpp"
namespace test {
int Subject::creationCount = 0;
Subject::Subject()
{
++creationCount;
std::cout << "Subject("<<creationCount<<")\n";
}
namespace {
TypeInfo<Subject> shall_build_a_Subject_instance;
}
/**
* instance of the singleton factory
* @note especially for this example we're using just \em one
* shared instance of the factory.
* Yet still, two (inlined) calls to the get() function might
* access different addresses for the embedded singleton instance
*/
AccessPoint fab(shall_build_a_Subject_instance);
Subject&
fabricate()
{
return fab.get();
}
} // namespace test
Holder<T,F>::get()
, 将看到静态变量的不同位置 instance
ConfigurableHolder
以要创建的单例的具体类型为模板,此特定类型信息被删除;它与 Adapter
的类型无关或 ConfigurableHolder
get()
的所有用法应该看到相同类型的 Holder
因此嵌入在 Holder
中的静态变量的位置相同sub2
调用工厂,这是从另一个编译单元调用的,而sub1
和 sub3
按预期共享相同的单例实例有趣的是,使用 Clang-3.0 构建的可执行文件的符号表显示此静态变量已链接两次(使用 Clang-3.2 时行为相同)
10: 0000000000000000 0 FILE LOCAL DEFAULT ABS research/clang-static-init-1.cpp
11: 0000000000400cd0 11 FUNC LOCAL DEFAULT 14 global constructors keyed to a
12: 0000000000400b70 114 FUNC LOCAL DEFAULT 14 test::Holder<test::Subject, test::Adapter<test::Subject>::AdaptedConfigurableFactory>::get()
13: 00000000004027e0 8 OBJECT LOCAL DEFAULT 28 test::Holder<test::Subject, test::Adapter<test::Subject>::AdaptedConfigurableFactory>::instance
14: 00000000004027d8 1 OBJECT LOCAL DEFAULT 28 std::__ioinit
15: 0000000000400b10 62 FUNC LOCAL DEFAULT 14 __cxx_global_var_init
16: 0000000000000000 0 FILE LOCAL DEFAULT ABS research/clang-static-init-2.cpp
17: 00000000004010e8 0 NOTYPE LOCAL DEFAULT 17 GCC_except_table9
18: 0000000000400e60 16 FUNC LOCAL DEFAULT 14 global constructors keyed to a
19: 00000000004027f9 1 OBJECT LOCAL DEFAULT 28 test::(anonymous namespace)::shall_build_a_Subject_instance
20: 0000000000400de0 114 FUNC LOCAL DEFAULT 14 test::Holder<test::Subject, test::Adapter<test::Subject>::AdaptedConfigurableFactory>::get()
21: 0000000000402800 8 OBJECT LOCAL DEFAULT 28 test::Holder<test::Subject, test::Adapter<test::Subject>::AdaptedConfigurableFactory>::instance
...而 GCC-4.7.2 编译的可执行文件的相关部分按预期读取
44: 0000000000400b8c 16 FUNC GLOBAL DEFAULT 14 localFunction()
45: 00000000004026dc 1 OBJECT GLOBAL DEFAULT 28 test::fab
46: 0000000000400c96 86 FUNC WEAK DEFAULT 14 test::Holder<test::Subject, test::Adapter<test::Subject>::AdaptedConfigurableFactory>::get()
47: 00000000004026e0 272 OBJECT GLOBAL DEFAULT 28 std::cout
48: 0000000000000000 0 FUNC GLOBAL DEFAULT UND std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(st
49: 0000000000400d4b 16 FUNC GLOBAL DEFAULT 14 test::fabricate()
50: 0000000000000000 0 FUNC GLOBAL DEFAULT UND std::basic_ostream<char, std::char_traits<char> >::operator<<(void const*)
51: 00000000004026d0 8 OBJECT UNIQUE DEFAULT 28 test::Holder<test::Subject, test::Adapter<test::Subject>::AdaptedConfigurableFactory>::instance
52: 0000000000400cec 15 FUNC WEAK DEFAULT 14 test::Adapter<test::Subject>::AdaptedConfigurableFactory<test::Subject>::create()
53: 00000000004026c8 8 OBJECT UNIQUE DEFAULT 28 test::Adapter<test::Subject>::factoryFunction
我们使用 Debian/stable 64bit(GCC-4.7 和 Clang-3.0)和 Debian/testing 32bit(Clang-3.2)来构建
最佳答案
修复方法是在外部声明您的单例模板类,并在单个编译单元中显式实例化单例。
如果您的编译单元位于单独的(共享)库中,那么 Clang 之所以这样做,只是因为它可以。
编译代码时,编译器会在每次完全指定时实例化单例模板。在链接时,除了一个实例之外的所有实例都被丢弃。但是,如果您的项目中有共享库,并且有多个链接时间,会发生什么情况?每个共享对象都将有一个模板实例。 GCC 确保在最终的可执行文件中只有一个幸存的模板实例化(可能使用 vague linkage ?),但显然 Clang 没有。
关于c++ - 从多个编译单元引用模板化静态变量时,Clang 链接到不同的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19212474/
我是 python 的新手。我试图找到我的文本的频率分布。这是代码, import nltk nltk.download() import os os.getcwd() text_file=open(
我对安卓 fragment 感到困惑。我知道内存 fragment 但无法理解什么是 android fragment 问题。虽然我发现很多定义,比如 Android fragmentation re
尝试对 WordPress 进行 dockerise 我发现了这个场景: 2个数据卷容器,一个用于数据库(bbdd),另一个用于wordpress文件(wordpress): sudo docker
这个问题已经有答案了: From the server is there a way to know that my page is being loaded in an Iframe (1 个回答)
我正在玩小型服务器,试图对运行在其上的服务进行docker化。为简化起见,假设我必须主要处理:Wordpress和另一项服务。 在Docker集线器上有许多用于Wordpress的图像,但是它们似乎都
我想要发生的是,当帐户成功创建后,提交的表单应该消失,并且应该出现一条消息(取决于注册的状态)。 如果成功,他们应该会看到一个简单的“谢谢。请检查您的电子邮件。” 如果不是,那么他们应该会看到一条适当
就是这样,我需要为客户添加一个唯一标识符。通过 strip 元数据。这就是我现在完全构建它的方式,但是我只有最后一部分告诉我用户购买了哪个包。 我试着看这里: Plans to stripe 代码在这
我有一个类将执行一些复杂的操作,涉及像这样的一些计算: public class ComplexAction { public void someAction(String parameter
这个问题已经有答案了: maven add a local classes directory to module's classpath (1 个回答) 已关闭10 年前。 我有一些不应更改的旧 E
我使用 fragment 已经有一段时间了,但我经常遇到一个让我烦恼的问题。 fragment 有时会相互吸引。现在,我设法为此隔离了一个用例,它是这样的: Add fragment A(也使用 ad
我的 html 中有一个 ol 列表,上面有行条纹。看起来行条纹是从数字后面开始的。有没有办法让行条纹从数字开始? 我已经包含了正在发生的事情的片段 h4:nth-child(even) {
如何仅使用 css 将附加图像 html 化? 如果用纯 css 做不到,那我怎么能至少用一个图像来做 最佳答案 这不是真正的问题,而是您希望我们为您编写代码。我建议您搜索“css breadcrum
以下是 Joshua 的 Effective Java 的摘录: If you do synchronize your class internally, you can use various te
在这里工作时,我们有一个框向业务合作伙伴提供 XML 提要。对我们的提要的请求是通过指定查询字符串参数和值来定制的。其中一些参数是必需的,但很多不是。 例如,我们要求所有请求都指定一个 GUID 来标
我有 3 个缓冲区,其中包含在 32 位处理器上运行的 R、G、B 位数据。 我需要按以下方式组合三个字节: R[0] = 0b r1r2r3r4r5r6r7r8 G[0] = 0b g1g2g3g4
我最近发现了关于如何使用 History.js、jQuery 和 ScrollTo 通过 HTML5 History API 对网站进行 Ajax 化的要点:https://github.com/br
我们有一个 Spring Boot 应用程序,由于集成需要,它变得越来越复杂——比如在你这样做之后发送一封电子邮件,或者在你之后广播一条 jms 消息等等。在寻找一些更高级别的抽象时,我遇到了 apa
我正在尝试首次实施Google Pay。我面临如何指定gateway和gatewayMarchantId的挑战。 我所拥有的是google console帐户,不知道在哪里可以找到此信息。 priva
昨天下午 3 点左右,我为两个想要从一个 Azure 帐户转移到另一个帐户的网站设置了 awverify 记录。到当天结束时,Azure 仍然不允许我添加域,所以我赌了一把,将域和 www 子域重新指
我正在使用terms facet在elasticsearch服务器中获取顶级terms。现在,我的标签"indian-government"不被视为一个标签。将其视为"indian" "governm
我是一名优秀的程序员,十分优秀!