c++ - 确定对象是否分配在静态内存块中(或如何避免数据竞争条件)

标签 c++ winapi

前言:

这个问题与这些问题密切相关:...
- C++: Avoiding Static Initialization Order Problems and Race Conditions Simultaneously
- How to detect where a block of memory was allocated?
...但他们没有正解决方案,我的实际目标用例略有不同。

在构建对象期间,我需要知道它是在静态内存块 (BSS) 中初始化还是在堆中实例化。

原因如下:

  • 对象本身被设计为在构造函数中初始化为“全零”——因此如果对象是静态初始化的,则不需要初始化——当加载程序时,包含所有对象的整个 block 已经设置为零。

  • 对象的静态实例可以被其他静态分配的对象使用,并改变对象的一些成员变量

  • 静态变量的初始化顺序is not pre-determined - 即我的目标对象可以在其构造函数被调用之前被调用,从而改变它的一些数据,并且构造函数可以稍后根据一些未知的静态初始化顺序被调用从而清除已经改变的数据。这就是为什么我想在构造函数中为静态分配的对象禁用代码。

  • 注意:在某些情况下,对象是严格多线程访问的对象(它有一些 InterlockedIncrement/Decrement 逻辑),并且它必须在任何线程可以接触它之前完全初始化 - 我可以保证如果我在 Heep 中显式分配它,但不在静态区域中(但我也需要它用于静态对象)。

示例代码来说明这个案例:

struct MyObject
{
    long counter;

    MyObject() {
        if( !isStaticallyAllocated() ) {
            counter = 0;
        }
    }
    void startSomething() { InterlockedIncrement(&counter); }
    void endSomething() { InterlockedDecrement(&counter); }
};

目前我正在尝试检查“this”指针是否在某个预定义范围内,但这不能可靠地工作。

LONG_PTR STATIC_START = 0x00400000;
LONG_PTR STATIC_END   = 0x02000000;
bool isStatic = (((LONG_PTR)this >= STATIC_START) && (LONG_PTR)this < STATIC_END));

更新: 显式新运算符不适用的示例用例。代码是“伪代码”,只是为了说明用例。

struct SyncObject() {
    long counter;
    SyncObject() { 
        if( !isStaticallyAllocated() ) {
            counter = 0;
        } }
    void enter() { while( counter > 0 ) sleep(); counter++; }
    void leave() { counter--; }
}

template <class TEnum>
struct ConstWrapper {
    SyncObject syncObj;
    TEnum m_value;

    operator TEnum() const { return m_value; }
    LPCTSTR getName() {
        syncObj.enter();
        if( !initialized ) {
            loadNames();
            intialized = true;
        }
        syncObj.leave();
        return names[m_value];
    }
}

ConstWrapper<MyEnum> MyEnumValue1(MyEnum::Value1); 

最佳答案

您可能可以通过为您的类覆盖 new 运算符来实现这一点。在您自定义的 new 中,您可以在分配的内存中设置一个“魔术字节”,稍后您可以检查它。这将不允许区分堆栈和堆,但静态地与动态分配的对象,这可能就足够了。但是请注意,在下面的情况下

class A {
};

class B {
   A a;
};

//...

B* b = new B;

b.a 将被视为使用建议的方法静态分配。

编辑:一个更简洁但更复杂的解决方案可能是对 new 的进一步自定义,您可以在其中跟踪动态分配的内存块。

第二次编辑:如果你只是想禁止静态分配,为什么不直接将构造函数设为私有(private)并向动态创建对象并传递指针的类添加一个工厂函数?

class A {
private:
    A () { ... }
public:
    static A* Create () { return new A; }
};

关于c++ - 确定对象是否分配在静态内存块中(或如何避免数据竞争条件),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13082019/

相关文章:

c++ - 命名空间内模板类的前向声明

c++ - 一个没有被操作过的 32 位归一化 float ,在任何平台/编译器上都是一样的吗?

c++ - 为什么我要重载 operator new 或 operator delete?

c++ - 嵌入文件打开对话框

c++ - Windows API的STL成员变量初始化问题

c++ - 使用可变参数包实例化函数模板

c++ - G++ 中的常量折叠

c++ - 如何使用CreateProcess在cmd中执行命令?

winapi - win32 对话框应用程序 : how to make the dialog box hidden on startup?

c++ - 可以放置一个钩子(Hook)来捕获子进程发送到控制台的消息吗?