操作符 new 和放置新操作后删除?

问题描述 投票:0回答:1

假设我想将一个对象放在“堆”上,但我需要在它之后分配一些额外的内存。

我的理解是,以下是符合标准的方法:

(暂时假设没有任何内容覆盖

new
,并且
SomeClass
的析构函数不会抛出)

#include <new>

void f(std::size_t n) {
    void* buf = ::operator new(sizeof(SomeClass) + n);
    SomeClass* obj = new(buf) SomeClass;

    // Do stuff with obj

    obj->~SomeClass();
    ::operator delete(buf);
}

但是假设我不想一直保留

buf
变量。也许我在一个函数中创建了该对象,然后在其他函数中销毁它,并且我不方便继续与
buf
一起传递
obj
。这样做是否有效:

#include <new>

void f(std::size_t n) {
    void* buf = ::operator new(sizeof(SomeClass) + n);
    SomeClass* obj = new(buf) SomeClass;

    // Do stuff with obj

    obj->~SomeClass();
    ::operator delete(static_cast<void*>(obj));
}

我无法从参考中最终确定由placement new返回的指针,如果转换为

void*
,是否被认为是由
operator new
返回的“相同”指针。

最后,这样的事情是否有可能有效:

#include <new>

void f(std::size_t n) {
    void* buf = ::operator new(sizeof(SomeClass) + n);
    SomeClass* obj = new(buf) SomeClass;

    // Do stuff with obj

    delete obj;
}

我认为它无效,但从技术上讲,

obj
是由
new
表达式返回的,并且它位于由
new
运算符分配的内存中,所以也许?

编辑:我刚刚想到,另一种方法是为

operator new
添加覆盖,然后在新的放置中使用它?换句话说,这样的东西有效吗:

#include <new>

enum class ExtraSpace : std::size_t {}; 

void* operator new(std::size_t size, ExtraSpace n) {
    return ::operator new(size + static_cast<std::size_t>(n));
}

void f(std::size_t n) {
    SomeClass* obj = new(ExtraSpace(n)) SomeClass;

    // Do stuff with obj

    delete obj;
}

(我正在使用 C++14,但也有兴趣了解其他标准的任何差异)

c++ c++14 language-lawyer
1个回答
0
投票
    void* buf = ::operator new(sizeof(SomeClass) + n);
    SomeClass* obj = new(buf) SomeClass;

    delete obj;

可能是C++14中未定义的行为([expr.delete]p10的措辞由CWG1788的决议修改):

如果释放函数查找既找到仅具有指针参数的普通释放函数,又找到具有指针参数和大小参数的普通释放函数,则按如下方式选择要调用的函数:

  • [对于数组
    delete[]
    ,...]
  • 否则,无法指定选择两个释放函数中的哪一个。

如果选择了未调整大小的

operator delete((void*) obj)
,那么就可以了。但是,如果选择了大小合适的
operator delete((void*) obj, sizeof(SomeClass))
,则会出现未定义的行为,因为该大小与传递给
operator new
的大小不同。

GCC 默认调用已调整大小的

operator delete(void*, std::size_t)
,Clang 默认调用未调整大小的
operator delete(void*)


至于

void* buf
变量,
void* operator new(std::size_t, void* ptr)
被专门定义为返回
ptr
不变([new.delete.placement]p2)。所以
obj
buf
具有相同的值(在 C++17 中指向相同的地址),因此
operator delete(static_cast<void*>(obj))
相当于
operator delete(buf)

© www.soinside.com 2019 - 2024. All rights reserved.