静态变量在 DLL 中定义的模板类用法中重复

问题描述

我在一个名为 TemplateT 的头文件中的 DLL 中有以下代码

#pragma once

template<class T>
class __declspec(dllexport) TemplateT {
public:
    static int number;
    TemplateT(int num) {
        number = num;
    }
    int getNumber() {
        return number;
    }

};
template<class T>
int TemplateT<T>::number;

以及另一个名为 Exported.h 的头文件

#pragma once
#include "TemplateT.h"


#define EXPORTED __declspec(dllexport)

extern EXPORTED TemplateT<int> exported;

在 Exported.cpp 上,我有

#include "Exporter.h"


TemplateT<int> exported(5);

如您所见,我将静态成员“number”初始化为值 5。 但是当我像这样从一个项目访问变量时:

#include <iostream>
#include "Exporter.h"

int main()
{
    int a = exported.getNumber();
    int b = 0;
}

我看到 number 的值为 0。 如果你能向我解释这种行为,我会很高兴。

编辑

两者都用visual studio 2019。dll是用vs19编译的,另一个项目用vs10

我发现了一个关于相同情况的问题,但那里的答案并没有为我解决

two instances of static member

解决方法

[SO]: DLL-Exporting static members of template base class 提供了答案。
您的类(和导出的变量)有 2 个静态成员实例:

  1. .dll (Exporter.cpp) 中 - 初始化(显式)为 5
  2. .exe (main.cpp) 中 - 初始化(默认)为 0(这是您实际看到的)

我复制了你的代码,做了一些小改动 - 最重要的是额外的(常规 .dll 导出)文件

导出.h

#pragma once

#if defined(_WIN32)
#  if defined(DLL0_STATIC)
#    define DLL0_EXPORT_API
#  else
#    if defined(DLL0_EXPORTS)
#      define DLL0_EXPORT_API __declspec(dllexport)
#    else
#      define DLL0_EXPORT_API __declspec(dllimport)
#    endif
#  endif
#else
#  define DLL0_EXPORT_API
#endif

以下是调试过程中截取的 2 个屏幕截图:

  1. 构造函数

    img00

  2. 吸气剂

    img01

number会员地址(红框),2张图不一样(注意实例地址(this)是一样的),所以有证明。

现在,从更大的角度来看,这似乎是一个XY 问题
我没有看到任何适合这种设计的场景(除了出于好奇目的),因为 静态成员设置为构造函数参数,这意味着新实例将覆盖先前设置的任何内容,因此在某个时间点,该成员将包含传递给最后一个实例构造函数的参数。

,

#include 指令的真正含义是包含。它有效地将包含的头文件的内容插入到源文件(.c/.cpp)中(递归)。

因此,当您(直接或间接)将 template.h 包含在多个源文件中时,每个源文件都会分配它自己的静态 number 文件。如果将这些源文件编译成一个目标文件,就会出现链接错误。但如果它们被编译成不同的 DLL/EXE,它们将保留自己的静态文件副本。

这类似于全局变量,您通常必须使用 extern 关键字告诉编译器这只是一个声明,而不是定义。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...