首页 > 解决方案 > NoFieldsClass::operator new(std::size_t):标准是否允许它每次调用时返回相同的地址?

问题描述

作为优化策略的一部分,我想“假装”我实际上是在堆上分配一个对象,而实际上我只是重用一个预先存在的对象,而应用程序的其余部分却没有注意到,因为没有检查在返回的地址上执行,并且不需要访问对象中的任何字段。除此之外,类构造函数没有副作用。

因此,我想知道以下程序是否表现出按照标准的定义明确、特定于实现、未定义或完全无效的行为。

#include <memory>
#include <cassert>

class Base {
public:
    Base(){}
    virtual ~Base(){}
};

class Derived: public Base {
public:
    using Base::Base;

    static void *operator new(std::size_t s)  {
        static void *mem = ::operator new(s);

        return mem;
    }

    static void operator delete(void *mem) {
        /* no-op */
    }
};

int main() {
    using Ptr = std::unique_ptr<Base>;

    Ptr p1 { new Derived };
    Ptr p2 { new Derived };
    Ptr p3 { new Derived };
    Ptr p4 { new Derived };

    // assert just in this test, not in the real program
    assert(p1 == p2 && p2 == p3 && p3 == p4);

    return 0;
}

阅读当前 C++ 工作草案(N4835)的 §6.7.2.9 似乎它是无效的:

如果一个对象嵌套在另一个对象中,或者至少一个是大小为零的子对象并且它们属于不同类型,则两个具有重叠生命周期且不是位域的对象可能具有相同的地址;否则,它们具有不同的地址并占用不相交的存储字节²⁹。

然而,上述段落所指的注释 29 指出:

在“as-if”规则下,如果程序无法观察到差异,则允许实现将两个对象存储在同一机器地址或根本不存储对象。

如开头所述,在我的情况下,程序并不关心分配此对象的地址,所需要的只是它可以分配operator new和摆脱 with operator delete,所以它似乎适合注释 29 提出的要求。这是正确的吗?

标签: c++memory-managementlanguage-lawyernew-operator

解决方案


[basic.stc.dynamic.allocation]/2分配函数尝试分配请求的存储量...如果请求成功,则返回的值应为p0 不同于任何先前返回值 的非空指针值(7.11)p1, 除非该值p1随后被传递给operator delete.

强调我的。


推荐阅读