非静态成员变量在静态对象中分配在哪里?

8

我有这段代码,我想知道内存分配情况。

 void f(){
        static A a;
        //Other things...
    }

    class A {
        public:
           A();
        private:
            AnotherObjectType anotherObject;
    };

anotherObject会分配在哪里?是在静态代码段还是其他地方?anotherObject被覆盖的风险是否存在?(f将被多次调用)。

5个回答

5
所有的非堆对象都会在静态 A 实例的静态段内。
关于覆写,这可能在旧的 C/C++ 中发生,如果您在多线程代码中使用各种单例习语。但是例如新版本的 gcc 使用自动线程安全初始化静态对象的新标准要求。请参见例如 C++11 中的本地静态变量初始化是否线程安全?

到目前为止唯一指出C++11之前和之后静态变量行为差异的答案。 - senfen
2
更准确地说,非“堆”实际上意味着非“动态”。如果使用自定义分配器,则动态分配的对象也可以在静态段中。 “堆”是一种实现细节,恰好是最常用的。 - Johann Gerell
请注意,我认为Visual C++在VS2015之前没有实现线程安全的静态初始化(魔术静态变量)。 - sjdowling
@Johann Gerell:很好的观点,了解自定义分配器非常重要。 - Erik Alapää

1

内存可以静态或动态分配。动态分配是在运行时使用newmalloc等方法分配内存。静态分配则是指其他情况下的内存分配。类成员变量的内存分配与类实例一起分配,因此如果是静态分配,成员变量将位于同一部分内存中;如果是动态分配,则成员变量将位于动态内存所在的位置。这对于指针成员变量也是适用的,但它指向的实际内存可以是动态分配的(使用newmalloc),也可以是静态分配的。

int i = 0;
int* pi = &i;     // pi points at statically allocated memory
pi = new int(0);  // pi points at dynamically allocated memory

所以,如果你有一个静态类实例,它和它的成员的内存通常是在代码段中分配的,但这是一个实现细节。

如果该成员是指向动态分配内存的指针,那么该内存将会被使用的分配器决定。"堆"是动态分配内存的最常见实现细节,通常使用newmalloc时会得到,但可以使用自定义分配器控制内存的其他位置,甚至在代码段中。


0
变量a是一个静态变量,只声明一次,这意味着A a;语句只执行一次。变量的作用域在函数f的作用域之上。字段anotherObject位于A对象的分配内部。
看一个计数的例子:
#include <iostream>
using namespace std;
class AnotherObjectType {};

class A {
public:
   A(){count = 0;};
    int count;
private:
    AnotherObjectType anotherObject;
};

 A f(){
    static A a;
    a.count++;
    //Other things...
    return a;
}

int main() {
    // your code goes here
    A a;
    for (int i = 0; i < 3; i++) {
        a = f();
        std::cout << "Count: " << a.count  << std::endl;
    }
    return 0;
}

工作示例:http://ideone.com/USqeEZ

另请参阅:http://www.learncpp.com/cpp-tutorial/811-static-member-variables/


0
void f(){
    /// this created in static segment - that's obviously for you
    static A a;
    //Other things...
}

class A {
    public:
       A();
    private:
        /// anotherObject is not pointer but explicit part of A,
        /// so it won't be created in heap or anywhere else,
        /// but in the same memory segment as an instance of A.
        AnotherObjectType anotherObject;
};

所以,anotherObject 不会被覆盖,因为 static A a 在静态段中创建了一个 A 的实例,任何其他实例将根据您创建它的段在其他段中创建。

为什么注释中没有解释就减去了?出了什么问题吗? - Alex Medveshchek
1
我给你点了赞,因为我对那个没有说明原因就给你点踩的“善良人士”感到烦恼...你有几个拼写错误,而且表述也不是很清晰,但我明白你的意思。 - Werner Erasmus
非常感谢您的解释。对不起,我的英语不太好。) - Alex Medveshchek

0

尽管都被称为“静态”,但静态成员与静态局部变量是不同的。

静态成员在类中共享。该类的每个实例都引用相同的成员。

静态局部变量只初始化一次,并且在函数返回时不会被销毁。

在您的代码中,非静态成员存储在实例a中,并且a在函数返回后仍然存在。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接