为什么标题中的单身人士不适用于Windows/Mingw?
以下是我的 PoC 代码:
ah: 它实现了一个单例方法来创建 A 实例
#pragma once
class A
{
public:
int a;
static A& Instance() {
static A a;
return a;
}
};
b.h: 它声明了一个函数将尝试在内部创建一个 A 实例,并输出它的地址。
#pragma once
void test_b();
b.cc:test_b
和 c.cc:test_c
的实现
#include "b.h"
#include <iostream>
#include "a.h"
void test_b() {
auto &a = A::Instance();
std::cout << "a address in test_b: " << (void *)(&a) << std::endl;
}
,与 test_b
执行相同的操作,并调用 test_b< /code> 和
main
中的 test_c
来检查单例是否正常工作。
#include <iostream>
#include "a.h"
#include "b.h"
void test_c() {
auto &a = A::Instance();
std::cout << "a address in test_c: " << (void *)(&a) << std::endl;
}
int main() {
test_b();
test_c();
return 0;
}
我使用b.cc在Windows(libb.dll)中构建共享库libb.so,并使用c.cc创建与共享库链接的test_app。
我已经在Linux和Windows(MinGW)中测试了上述代码,但得到了不同的结果。
在 linux 下,输出如下:
a address in test_b: 0x601174
a address in test_c: 0x601174
在 MinGW 下,输出如下:
a address in test_b: 0x7ff87df93070
a address in test_c: 0x7ff731ef30b0
我用于构建的 makefile。
Makefile:
test_app: c.cc libb.so
g++ -o $@ $^ -lb
libb.so: a.h b.cc
g++ -o $@ -fPIC -shared b.cc
Makefile.mingw
test_app.exe: c.cc libb.dll
g++ -o $@ $^ -lb -L.
libb.dll: a.h b.cc
g++ -o $@ -fPIC -shared b.cc
我知道在头文件中实现 Singleton 不是一个好的做法,但是如果有人可以帮助解释原因吗?
Here are my codes for PoC:
a.h: which implements a singleton method to create A instance
#pragma once
class A
{
public:
int a;
static A& Instance() {
static A a;
return a;
}
};
b.h: which declares a function will try to create an A instance inside, and output the address of it.
#pragma once
void test_b();
b.cc: The implementation of test_b
#include "b.h"
#include <iostream>
#include "a.h"
void test_b() {
auto &a = A::Instance();
std::cout << "a address in test_b: " << (void *)(&a) << std::endl;
}
and c.cc: test_c
which do the same things as test_b
, and call test_b
and test_c
in main
to check if the singleton is working.
#include <iostream>
#include "a.h"
#include "b.h"
void test_c() {
auto &a = A::Instance();
std::cout << "a address in test_c: " << (void *)(&a) << std::endl;
}
int main() {
test_b();
test_c();
return 0;
}
I using the b.cc to build a shared library libb.so in windows(libb.dll), and using c.cc to create the test_app which links with the shared library.
I've tested the above codes in Linux and Windows(MinGW), but I've got different results.
Under linux the output is like:
a address in test_b: 0x601174
a address in test_c: 0x601174
And under MinGW the output is like:
a address in test_b: 0x7ff87df93070
a address in test_c: 0x7ff731ef30b0
The makefile I used for the build.
Makefile:
test_app: c.cc libb.so
g++ -o $@ $^ -lb
libb.so: a.h b.cc
g++ -o $@ -fPIC -shared b.cc
Makefile.mingw
test_app.exe: c.cc libb.dll
g++ -o $@ $^ -lb -L.
libb.dll: a.h b.cc
g++ -o $@ -fPIC -shared b.cc
I know implementing Singleton in the header file is not a good practice, but if anyone could help to explain why?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
就语言而言,
A::Instance
返回的左值必须始终引用程序执行过程中的同一对象。如果一种语言的实现偏离了这一点,那么它就不符合标准。您正在使用共享库,它是该语言的扩展。正如您所见,使用此语言扩展会导致语言实现偏离标准所提供的保证。
您可以通过将实例 getter 定义为单个翻译单元中的非内联函数而不是内联函数来解决此问题。另一种方法是根据语言实现的文档(MSVC 中的
dllexport
、dllimport
)使用语言实现特定的函数属性来控制共享库行为。旁注:单例模式要求封装该类,以便除了静态实例之外不能创建任何实例。该示例只是一个静态本地对象,从技术上讲,它不是单例,因为构造函数没有封装。
As far as the language is concerned, the lvalue returned by
A::Instance
must always refer to the same object within the execution of the program. If a language implementation deviates from that, then it doesn't conform to the standard.You are using shared libraries which are an extension of the language. As you've witnessed, using this language extension causes the language implementation to deviate from the guarantees given by the standard.
You can work around the issue by defining the instance getter as a non-inline function in a single translation unit, rather than as an inline function. Another way is to use language implementation specific function attributes to control the shared library behaviour as per the documentation of the language implementation (
dllexport
,dllimport
in MSVC).Sidenote: Singleton pattern requires that the class is encapsulated such that no instances besides the static one can be created. The example is just a static local object and technically not a singleton since the constructor isn't encapsulated.