在静态库和 DLL 中使用静态成员 - 成员值正在重置

mik*_*uld 7 c++ dll static-members static-libraries dllexport

我有一个包含 3 个项目的解决方案:

  • Lib1(静态库)
  • Dll1(动态库)
  • App1(空白的 Windows 应用商店应用程序,可以是任何应用程序类型)

Lib1 包含以下内容:

导出.h

#pragma once

#ifdef DLL_EXPORT
    #define EXPORT __declspec(dllexport)
#else
    #define EXPORT __declspec(dllimport)
#endif
Run Code Online (Sandbox Code Playgroud)

库1.h

#pragma once
#include "Export.h"

class Member { };

class EXPORT Base {
public:
    static Member* GetStaticMember();
    virtual void SetMember(Member* member) = 0;

protected:
    static Member* m_member;
};

class Worker {
public:
    void DoSomething();
};
Run Code Online (Sandbox Code Playgroud)

库1.cpp

#include "pch.h"
#include "Lib1.h"

Member* Base::m_member;

Member* Base::GetStaticMember() {
    return m_member;
}

void Worker::DoSomething() {
    Member* test = Base::GetStaticMember(); // RETURNS 0
}
Run Code Online (Sandbox Code Playgroud)

Dll1包含以下内容

DLL1.h

#pragma once
#include "Lib1.h"
#include "Export.h"

class EXPORT ChildA : public Base {
public:
    virtual void SetMember(Member* member) override;
};
Run Code Online (Sandbox Code Playgroud)

DLL1.cpp

#include "pch.h"
#include "Dll1.h"

void ChildA::SetMember(Member* member) {
    Base::m_member = member;

    Member* test = Base::GetStaticMember(); // RETURNS CORRECT ADDRESS
}
Run Code Online (Sandbox Code Playgroud)

App1包含以下内容

Member* member = new Member();
ChildA* childa = new ChildA();
childa->SetMember(member); // Base::GetStaticMember() inside this RETURNS CORRECT ADDRESS

Worker* worker = new Worker();
worker->DoSomething(); // Base::GetStaticMember() inside this RETURNS 0
Run Code Online (Sandbox Code Playgroud)

问题

在调试器中单步执行时,Base::GetStaticMember() 在设置成员后返回正确的地址(但仍在 childa->SetMember() 内)。一旦在 OUTSIDE childa 中,Base::GetStaticMember() 将返回 0。当在worker->DoSomething()内部时,Base::GetStaticMember()也返回0。任何人都可以向我解释一下这是什么原因以及如何修复它,以便在外部或内部方法中访问Base::GetStaticMember() Dll 或 Lib 的地址将返回正确的地址而不是 0?

Who*_*aig 3

如果您使用链接到多个 DLL 和/或 EXE 的静态库,则每个 DLL 都会获得自己静态成员变量。想想其中每一个的 *link 阶段如何发生的机制,您就会明白原因。

可以将静态变量转换为引用内存映射文件支持的共享内存的指针,但我警告您管理起来会很棘手。我通过使用类+成员+pid 的名称作为映射名称来维护临时内存映射文件来完成此操作(注意:pid 是为了允许多个进程运行而不会破坏彼此共享的内存)。它的效果出奇的好。

  • @mikeschuld Lib1.dll 而不是 Lib1.lib static-lib 可能会解决您现在的所有问题。它将确保在任何给定的单个进程中,全局数据空间(包括类的静态类成员)中的任何数据只有一份副本。您可以让正在运行的 app.exe 使用 Dll1.dll、Dll2.dll 等,最终使用它们的应用程序将在其地址空间中获得一个 Lib1.dll、其代码和数据。它解决了您遇到的静态库多副本问题,但确实引入了额外的 DLL 依赖项 (lib1.dll)。如果这对你有用,那么你就可以开始了。 (2认同)