C++ 静态函数中的静态变量能否移动到内存中的新地址?

C++ 静态函数中的静态变量能否移动到内存中的新地址?,c++,C++,我刚刚升级到一个新版本的第三方库(Qt5.0版的QtPropertyBrowser)。升级导致了我的应用程序中的一个新错误,我设法跟踪到库中的一个静态函数。该函数包含一个静态变量,该变量在第一次调用该函数时初始化。我在初始化后复制了该变量的内存位置,正如预期的那样,在多次后续调用中发现该变量仍保留在同一内存位置。然后在随后的函数调用中,我注意到静态变量中的内存位置和数据发生了变化(导致程序中出现错误) 代码如下所示: class ClassA { //.... }; class Cl

我刚刚升级到一个新版本的第三方库(Qt5.0版的QtPropertyBrowser)。升级导致了我的应用程序中的一个新错误,我设法跟踪到库中的一个静态函数。该函数包含一个静态变量,该变量在第一次调用该函数时初始化。我在初始化后复制了该变量的内存位置,正如预期的那样,在多次后续调用中发现该变量仍保留在同一内存位置。然后在随后的函数调用中,我注意到静态变量中的内存位置和数据发生了变化(导致程序中出现错误)

代码如下所示:

class ClassA
{
    //.... 
};

class ClassB
{
public:
    ClassA* ptrMember;
};

static ClassA *theFunction()
{
    static ClassB statVar = {0};
    if(!statVar.ptrMember)
        statVar.ptrMember = new ClassA();
    return statVar.ptrMember;
}
我发现在多次调用
theFunction()
的过程中,存储在
&statVar
中的地址始终保持不变,但在随后的一次调用中,
&statVar
中的地址不同,
statVar.ptrMember
为空

我认为这是不可能的!有什么想法吗?

看起来您已经在头文件中定义了函数,并且包含在许多
.cpp
文件中(每个
.cpp
文件定义了一个翻译单元)

由于函数声明为
static
,因此每个翻译单元都有自己的版本以及
static
变量。这就是为什么当您从不同的转换单元调用函数时,静态变量的地址是不同的。只要你从同一个翻译单位打电话,你就会看到同一个地址

请注意,对于特定的翻译单元,地址将保持不变。只是每个翻译单元都有自己的静态变量版本,因此地址不同;您不再访问同一个变量,它们是具有相同标识符的不同变量



问题是,这些都是在第三方库中定义的,我需要在不重新初始化静态变量的情况下从dll和exe调用它。有没有什么方法可以在不改变库中代码的情况下解决这个问题?我目前正在将库用作.lib。如果我把它编译成.dll,问题会消失吗

为了避免静态函数的多个版本(因此是静态变量),您需要从同一个转换单元调用它。要做到这一点,可以使用proxy调用函数。也就是说,不是直接调用函数,而是调用代理(它是在单个翻译单元中定义的,没有更多版本)

  • 在标头中声明代理:

    //proxy.h
    ClassA *proxy_of_theFunction();
    
  • 在实现文件中定义代理:

    //proxy.cpp
    ClassA* proxy_of_theFunction()
    {
        return theFunction(); //call the actual function
    }
    
调用函数的代理。那应该能解决你的问题

由于函数的是而非
静态
(它在proxy.cpp中定义),因此它只有一个版本;没有其他版本。由于只有一个代理可以调用
theFunction()
,因此每次调用的
theFunction
都是相同版本的,因此每次调用都会看到相同版本的
static
变量。:-)

看起来您已经在头文件中定义了函数,并且包含在许多
.cpp
文件中(每个
.cpp
文件定义了一个翻译单元)

由于函数声明为
static
,因此每个翻译单元都有自己的版本以及
static
变量。这就是为什么当您从不同的转换单元调用函数时,静态变量的地址是不同的。只要你从同一个翻译单位打电话,你就会看到同一个地址

请注意,对于特定的翻译单元,地址将保持不变。只是每个翻译单元都有自己的静态变量版本,因此地址不同;您不再访问同一个变量,它们是具有相同标识符的不同变量



问题是,这些都是在第三方库中定义的,我需要在不重新初始化静态变量的情况下从dll和exe调用它。有没有什么方法可以在不改变库中代码的情况下解决这个问题?我目前正在将库用作.lib。如果我把它编译成.dll,问题会消失吗

为了避免静态函数的多个版本(因此是静态变量),您需要从同一个转换单元调用它。要做到这一点,可以使用proxy调用函数。也就是说,不是直接调用函数,而是调用代理(它是在单个翻译单元中定义的,没有更多版本)

  • 在标头中声明代理:

    //proxy.h
    ClassA *proxy_of_theFunction();
    
  • 在实现文件中定义代理:

    //proxy.cpp
    ClassA* proxy_of_theFunction()
    {
        return theFunction(); //call the actual function
    }
    
调用函数的代理。那应该能解决你的问题


由于函数的是而非
静态
(它在proxy.cpp中定义),因此它只有一个版本;没有其他版本。由于只有一个代理可以调用
theFunction()
,因此每次调用的
theFunction
都是相同版本的,因此每次调用都会看到相同版本的
static
变量。:-)

上面哪一部分在头文件和cpp文件中?最初,所有内容都在头文件中模板化,并使用复杂的宏调用。为了调试正在发生的事情,我复制了没有模板或宏的类和函数,并将它们全部放在相关的.cpp文件中。这两种情况下的问题是相同的。为了澄清,您是说静态变量本身的地址(
&statVar
)发生了变化?或者它内部指向
ClassA
的指针发生了变化?第二个很容易解释,因为每次调用函数时都会覆盖它;第一个更神秘,你创建了一个新的
ClassA