【问题标题】:C++ static variable multiple instancesC++静态变量多实例
【发布时间】:2013-11-21 20:34:02
【问题描述】:

我遇到了以下奇怪的情况:我设法拥有一个带有两个实例的全局静态变量...这是正常的还是编译器中的错误还是 C++ 的隐藏领域?以下复制是从一个更大的项目中提取的(行为相同),显然更改了名称以保护罪魁祸首(是的,我知道这段代码中存在内存泄漏)。

代码来了:

// other.h
#ifndef _OTHER_H_
#define _OTHER_H_

struct other
{
    long longer;
    int inter;
    char charer;
};

void dosomething();

#endif

// other.cpp
#include "other.h"
#include "util.h"

void dosomething()
{
  other* something = alloc_mem(other, 4);
}

// util.h
#ifndef _UTIL_H_
#define _UTIL_H_

#include <memory.h>
#include <string>

#include "test_class.h"

template <class T> T* allocate(size_t count, const char* f, long l, const char* sth)
{
    T* tmp = new T[count];
    memset(tmp, 0, count * sizeof(T));
    test_class<T*>::instance().throwIn(tmp, f, l, sth, count);

    return tmp;
}

#define alloc_mem(type,count) allocate<type>(count, __FILE__, __LINE__, (char*)0)

#endif

// main.cpp
#include "other.h"  
#include "util.h"

int main()
{
  int* i = alloc_mem(int, 1);
  int* i1 = alloc_mem(int, 20);
  char* c = alloc_mem(char, 1);

  dosomething();
  int* i3 = alloc_mem(int, 1);
}

还有主要部分:

// test_class.h
#ifndef test_class_H
#define test_class_H
#include <stdlib.h>
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>

static long int all_alloc = 0; // THIS will get linked in two times!

template <typename T>
class test_class
{
private:
    test_class() {}
    static test_class<T>* pinstance;

public:
    ~test_class() {}
    static test_class& instance() {
        if(pinstance == NULL) {
            pinstance = new test_class();
        }
        return *pinstance;
    }

    void throwIn(T item, const char* file, long line, const char* _compiler, long count) {
        int status;
        char* s = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status) ;
        std::cout << "request:" << sizeof(T) * count << " bytes, type:" << s << " @ "<< 
                 file << ":" << line << " global_addr:" << &all_alloc << std::endl;
        all_alloc += sizeof(T) * count ;
        free(s);
        std::cout<<"All memory:" << all_alloc << std::endl;
    }
};

template <class T> test_class<T>*  test_class<T>::pinstance = NULL;

#endif

因此,您必须将其编译为:

g++ main.cpp other.cpp -o test

然后运行它,然后:

$ ./test
request:8 bytes, type:int* @ main.cpp:6 global_addr:0x6022d8
All memory:8
request:160 bytes, type:int* @ main.cpp:7 global_addr:0x6022d8
All memory:168
request:8 bytes, type:char* @ main.cpp:8 global_addr:0x6022d8
All memory:176
request:32 bytes, type:other* @ other.cpp:6 global_addr:0x6022f8
All memory:32
request:8 bytes, type:int* @ main.cpp:11 global_addr:0x6022d8
All memory:184

所以,正如我非常惊讶地看到的那样,我有两个all_alloc 的全球地址...确实,nm -C test 显示:

00000000006022d8 b all_alloc
00000000006022f8 b all_alloc

那么,很明显的问题:

为什么?这怎么可能?是否有允许这种行为的东西,或者这是编译器或链接器中的某个错误?

【问题讨论】:

  • 这个“test_class.h”直接在您提出问题的静态上方是一个相当强的指标,它位于标题中,您的命令行建议两个源文件包含它,每个源文件都有自己的all_alloc .每个包含test_class.h 的文件都将获得自己的all_alloc
  • 这不是问题,但是以下划线开头后跟大写字母 (_OTHER_H_) 的名称和包含两个连续下划线的名称保留给实现。不要使用它们。

标签: c++ templates static linker g++


【解决方案1】:

在这种情况下,我认为您不想将 all_alloc 声明为静态。在这种情况下,这意味着链接是内部的。在您的情况下,您会得到两个副本,因为两个文件包含标题。

如果您删除static,那么您将有两个副本冲突,并导致链接器错误。哪个不好。

我相信您要做的是将static 更改为extern,然后在一个 cpp 文件中定义变量及其值。

标题:

extern long int all_alloc;

cpp:

long int all_alloc = 0;

这将提供一份all_alloc 在您的代码之间共享的副本。

【讨论】:

    【解决方案2】:

    当你有全局变量时,它已经有静态持续时间,所以static 关键字对它来说意味着不同的东西。由于您在文件中有类定义,因此您定义了全局静态变量,我假设这是一个标题。为什么在标题中使用静态全局变量是个坏主意,你会得到什么你可以阅读here 所以答案是:这是预期的行为,而不是错误。

    【讨论】:

      猜你喜欢
      • 2014-02-03
      • 1970-01-01
      • 1970-01-01
      • 2019-03-28
      • 2011-12-29
      • 2014-02-07
      • 1970-01-01
      • 2016-09-15
      • 1970-01-01
      相关资源
      最近更新 更多