放置到缓冲区之后,缓冲区和实例是否具有相同的void *地址?

时间:2018-01-09 07:57:44

标签: c++ c++11 language-lawyer placement-new

请参阅以下代码:

unsigned char* p = new unsigned char[x];
CLASS* t = new (p) CLASS;
assert((void*)t == (void*)p);

我可以假设(void*)t == (void*)p吗?

2 个答案:

答案 0 :(得分:12)

是的,你可以。我相信它有几个条款的保证。

  1. [expr.new]/10 - 强调我的

      

    new-expression传递请求的空间量   allocation函数作为std :: size_t类型的第一个参数。的即   参数应不小于正在创建的对象的大小;   它可能大于正在创建的对象的大小   对象是一个数组。对于char和unsigned char的数组,   new-expression的结果与地址之间的差异   由分配函数返回的应是整数倍   任何最严格的基本对齐要求([basic.align])   对象类型,其大小不大于数组的大小   创建。 [注意:因为假定分配函数返回   存储指针,适用于任何对象的对齐   具有基本对齐的类型,这种对数组分配的约束   开销允许分配字符数组的常用习惯用法   稍后将放置其他类型的对象。 - 结束说明]

    对我而言,新表达式必须在分配函数返回的确切地址处创建一个对象(假设它不是数组类型)。由于您使用的是内置展示位置新功能,因此我们将使用以下内容

  2. [new.delete.placement]

      

    这些函数是保留的,C ++程序可能无法定义函数   取代标准C ++库中的版本   ([约束])。 ([basic.stc.dynamic])的规定不适用   这些保留的运营商新格式和运营商删除格式。

    void* operator new(std::size_t size, void* ptr) noexcept;
    
         

    返回:ptr。

         

    备注:故意不执行任何其他操作。

    这保证传递给表达式的地址是您分配的字符数组对象的确切地址。这是因为转换为void*不会更改源地址。

  3. 我认为它足以承诺地址是相同的,即使指针通常不可互换。所以根据[expr.eq]/1(感谢@ T.C。):

      

    同一类型的两个指针比较相等,当且仅当它们相同时   两者都为null,都指向相同的函数,或都表示相同   地址([basic.compound])。

    比较必须产生真,再次因为地址相同。

答案 1 :(得分:8)

  

我可以假设(void*)t == (void*)p吗?

不一定。

例如,如果类的作者重载CLASS::operator new(size_t, unsigned char*),那么该运算符可以返回除第二个参数之外的任何内容,例如:

struct CLASS
{
    static void* operator new(size_t, unsigned char* p) { return p + 1; }
};

如果您希望此新表达式调用the standard non-allocating placement new operator,则代码需要

  1. 包含标题<new>
  2. 确保传递void*参数。
  3. 使用范围解析运算符::对其进行前缀,以绕过CLASS::operator new,如果有的话。
  4. E.g:

    #include <new> 
    #include <cassert> 
    
    unsigned char p[sizeof(CLASS)];
    CLASS* t = ::new (static_cast<void*>(p)) CLASS;
    assert(t == static_cast<void*>(p));
    

    在这种情况下t == static_cast<void*>(p)确实。

    事实上,这就是GNU C ++标准库的作用:

    template<typename _T1, typename... _Args>
    inline void _Construct(_T1* __p, _Args&&... __args) { 
        ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); 
    }