为什么标题中的单身人士不适用于Windows/Mingw?

发布于 2025-01-20 15:57:43 字数 1872 浏览 0 评论 0原文

以下是我的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

找个人就嫁了吧 2025-01-27 15:57:43

就语言而言,A::Instance 返回的左值必须始终引用程序执行过程中的同一对象。如果一种语言的实现偏离了这一点,那么它就不符合标准。

为什么?

您正在使用共享库,它是该语言的扩展。正如您所见,使用此语言扩展会导致语言实现偏离标准所提供的保证。

您可以通过将实例 getter 定义为单个翻译单元中的非内联函数而不是内联函数来解决此问题。另一种方法是根据语言实现的文档(MSVC 中的dllexportdllimport)使用语言实现特定的函数属性来控制共享库行为。


旁注:单例模式要求封装该类,以便除了静态实例之外不能创建任何实例。该示例只是一个静态本地对象,从技术上讲,它不是单例,因为构造函数没有封装。

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.

why?

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文