c++ - 从类级放置新重载中访问成员

标签 c++

从类中定义的 placement-new 重载访问类的数据成员是否合法?

#include <iostream>
#include <cstdlib>

using namespace std;

class MyClass
{
public:

    MyClass ()
    {
        // Non-default constructor to make sure m_BaseAddress doesn't get
        // overwritten.
    }

    // T is some class that directly or indirectly inherits from MyClass.
    template<typename T>
    static void* operator new (size_t /* numBytes */, T* memory)
    {
        auto object = static_cast<MyClass*>(memory);
        object->m_BaseAddress = memory;
        return static_cast<void*>(memory);
    }

    template<typename T>
    static void operator delete (void* /* memory */, T* /* memory */)
    {
    }

    void* GetBaseAddress ()
    {
        return m_BaseAddress;
    }

private:

    void* m_BaseAddress;
};

int wmain ()
{
    auto memory = reinterpret_cast<MyClass*>(malloc(sizeof(MyClass)));

    auto object = new (memory) MyClass();

    wcout << L"Expected: " << memory << endl;
    wcout << L"Actual: " << object->GetBaseAddress() << endl;

    return 0;
}

我正在使用模板化的 placement-new 来尝试使其工作,即使正在“更新”的是从 MyClass 继承的类的实例。

用例:我使用特殊的分配器为对象分配内存。如果我给它分配内存的基地址,我可以从这个分配器查询一些与分配内存相关的辅助属性。为了处理这个基地址的新放置和存储,我使用一个类(上面示例中的 MyClass)作为所有需要在这个特殊堆上分配的类的基类.由于 placement-new 已经将基地址作为参数获取,我想知道是否可以直接设置成员,而不是要求在构造函数中也将其作为参数传递。

最佳答案

您发布的代码具有未定义的行为,在运行构造函数之前使用了放置 new 。这意味着您在 MyClass 的构造函数运行之前引用了 MyClass::m_BaseAddress,因此 static_cast 是一个谎言,程序是无效。

标准在 3.8.5 对象生命周期 部分明确指出这是未定义的行为(强调我的)。

Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a pointer refers to allocated storage (3.7.4.2), and using the pointer as if the pointer were of type void*, is well-defined. Such a pointer may be dereferenced but the resulting lvalue may only be used in limited ways, as described below. The program has undefined behavior if:
• the object will be or was of a class type with a non-trivial destructor and the pointer is used as the operand of a delete-expression,
the pointer is used to access a non-static data member or call a non-static member function of the object

您可以通过添加 some prints to your code 来看到发生了什么.

该程序可能会很好地处理这种未定义的行为,但它仍然是一个无效的 C++ 程序,应该避免。

请忽略此答案之前的编辑:(

关于c++ - 从类级放置新重载中访问成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35125956/

相关文章:

C++实现循环宏的方法

c++ - 遍历 vector 并删除内容

c++ - MSVC 2012 RC std::thread 实现中的最大参数数?

c++ - 重载赋值运算符不适用于链接

c++ - 获取被删除文件名的API

c++ - 在 GCC 与 MSVC2010 中的 init 上调用基类构造函数

c++ - QTableView 如何突出显示鼠标悬停的整行?

c++ - *绘制* std::vector<double> 的简单/最简单方法是什么?

c++ - linux下无法打开串口

c++ - 在 FreeBSD 上构建 lxml 示例时未定义对 glib 的引用