После размещения нового в буфере у буфера и экземпляра одинаковый адрес void *?

Пожалуйста, посмотрите код ниже:

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

Могу я предположить (void*)t == (void*)p?


person ravin.wang    schedule 09.01.2018    source источник
comment
AFAIK да, если T не является массивом.   -  person HolyBlackCat    schedule 09.01.2018
comment
Есть ли в спецификации C ++ какое-либо определение, гарантирующее это?   -  person ravin.wang    schedule 09.01.2018
comment
Соответствующий, возможный дубликат? stackoverflow.com/questions/47653305/   -  person StoryTeller - Unslander Monica    schedule 09.01.2018
comment
Он отличается, в вашей ссылке он сравнивает указатели экземпляров 2 классов, в этом сообщении он хочет сравнить исходный адрес буфера и адрес указателя экземпляра класса нового размещения.   -  person ravin.wang    schedule 09.01.2018
comment
Насколько я помню, обычная новая функция размещения объектов определяется как просто возвращающая указатель аргумента.   -  person Cheers and hth. - Alf    schedule 09.01.2018


Ответы (2)


Да, ты можешь. Я считаю, что это гарантировано несколькими положениями.

  1. # P2 #
    # P3 #
    # P4 #
  2. # P5 #
    # P6 #
    void* operator new(std::size_t size, void* ptr) noexcept;
    
    # P7 # # P8 #
    # P9 #

Думаю, достаточно пообещать, что адреса одинаковые, даже если указатели вообще не взаимозаменяемы. Итак, согласно [expr.eq] / 1 (благодаря @TC):

Два указателя одного типа сравниваются как равные тогда и только тогда, когда они оба равны нулю, оба указывают на одну и ту же функцию или оба представляют один и тот же адрес ([basic.compound]).

Сравнение должно дать истину, опять же, потому что адреса совпадают.

person StoryTeller - Unslander Monica    schedule 09.01.2018
comment
Кажется, что MSVC возвращает другой указатель при создании массивов с новым размещением: stackoverflow.com/questions/15254/ - person HolyBlackCat; 09.01.2018
comment
@HolyBlackCat - Да, это темный угол, в который я не хочу заходить. Если T оказывается массивом, я удаляю это. - person StoryTeller - Unslander Monica; 09.01.2018
comment
Я не думаю, что вам следует удалять это в любом случае, это хороший ответ. Также я обнаружил следующее: [expr.new] 1 Если сущность не является объектом массива, новое-выражение возвращает указатель на созданный объект. Если это массив, новое-выражение возвращает указатель на начальный элемент массива. Похоже, это разрешает странную обработку массивов в MSVC. - person HolyBlackCat; 09.01.2018
comment
@HolyBlackCat - я думаю, что примечание в первом процитированном абзаце объясняет, почему. Это позволяет выровнять массивы char по любому объекту, как предполагается для памяти, возвращаемой operator new. - person StoryTeller - Unslander Monica; 09.01.2018
comment
Наконец, [expr.eq] /2.2 говорит, что, за исключением, не относящимся к данному случаю, два указателя сравниваются как равные, если они представляют один и тот же адрес (даже если их значения различны, как здесь). - person T.C.; 09.01.2018

Могу я предположить (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; }
};

Если вы хотите, чтобы это новое выражение вызывало стандартный оператор new для размещения без выделения ресурсов, код должен

  1. Включить заголовок <new>.
  2. Обязательно передайте ему void* аргумент.
  3. Приставьте к нему префикс оператора разрешения области видимости ::, чтобы обойти CLASS::operator new, если таковой имеется.

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)...); 
}
person Maxim Egorushkin    schedule 09.01.2018