Для чего нужна декларация operator new/delete в private секции класса?
От: s.d.s Россия  
Дата: 30.10.15 09:24
Оценка:
Проект QtScript.
Есть участок кода, который можно свести вот к такому:

class Obj {
public:
    Obj() {
        cout << "Obj()" << endl;
    }
    ~Obj() {
        cout << "~Obj()" << endl;
    }
    void* operator new(size_t sz) {
        cout << "operator new(size_t)" << endl;
        return ::operator new(sz);
    }
    void operator delete(void* p) {
        cout << "operator delete(void*)" << endl;
        ::operator delete(p);
    }
private:
    friend class MyClass;
    void* operator new(size_t, void*);
    void operator delete(void*, size_t);
};

class MyClass {
public:
    MyClass() : m_(new Obj) {
        cout << "MyClass()" << endl;
    }
    ~MyClass() {
        cout << "~MyClass()" << endl;
        delete m_;
    }
private:
    const Obj * m_;
};


1. Какие возможные цели преследует декларация operator new(size_t, void*), operator delete(void*, size_t) в классе Obj

a) если смотреть по стандарту < C++14
b) >= C++14

2. MSVC 2015 выдает ошибку

error LNK2001: unresolved external symbol "private: static void __cdecl Obj::operator delete(void *,unsigned int)"


Будет ли для него равнозначной замена?

enum class Obj_tag : size_t {};
void operator delete(void*, Obj_tag);
Re: Для чего нужна декларация operator new/delete в private секции класса?
От: T4r4sB Россия  
Дата: 30.10.15 09:28
Оценка:
Здравствуйте, s.d.s, Вы писали:

SDS>1. Какие возможные цели преследует декларация operator new(size_t, void*), operator delete(void*, size_t) в классе Obj


Залоггировать создание-удаление в куче, наверное.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re: Для чего нужна декларация operator new/delete в private секции класса?
От: VTT http://vtt.to
Дата: 30.10.15 09:49
Оценка:
SDS>1. Какие возможные цели преследует декларация operator new(size_t, void*), operator delete(void*, size_t) в классе Obj
я бы разделил это вопрос на две части:
какой эффект от этой декларации? — экземпляры класса можно создавать только на куче или на стеке, а задействовать placement new не получится, чем отсекается всякое баловство навроде явного вызова деструктора с последующим созданием нового объекта на месте старого, а заодно становится невозможным использовать для хранения класса контейнеры, использующие placement new для создания объектов в собственноручно выделенной памяти.
зачем добавлять такие ограничения? — хз, это надо у автора кода спрашивать

В стандарте вроде по поводу этих операторов ничего не менялось, но это надо смотреть. Если уж хочется что-то запрещать, то наверное лучше пометить как = delete.

еще стоит отметить, что автор забил на перегрузку new[] и delete[]
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re: Для чего нужна декларация operator new/delete в private секции класса?
От: Stanislav V. Zudin Россия  
Дата: 30.10.15 09:55
Оценка:
Здравствуйте, s.d.s, Вы писали:

SDS>Проект QtScript.

SDS>Есть участок кода, который можно свести вот к такому:

SDS>
SDS>class Obj {
SDS>public:
SDS>    Obj() {
SDS>        cout << "Obj()" << endl;
SDS>    }
SDS>    ~Obj() {
SDS>        cout << "~Obj()" << endl;
SDS>    }
SDS>    void* operator new(size_t sz) {
SDS>        cout << "operator new(size_t)" << endl;
SDS>        return ::operator new(sz);
SDS>    }
SDS>    void operator delete(void* p) {
SDS>        cout << "operator delete(void*)" << endl;
SDS>        ::operator delete(p);
SDS>    }
SDS>private:
SDS>    friend class MyClass;
SDS>    void* operator new(size_t, void*);
SDS>    void operator delete(void*, size_t);
SDS>};

SDS>


SDS>1. Какие возможные цели преследует декларация operator new(size_t, void*), operator delete(void*, size_t) в классе Obj


Запретили использовать Placement new.
По каким-то внутренним причинам нельзя создавать vector<Obj>, например.

Зато можно создать объект в куче и держать его за указатель.
_____________________
С уважением,
Stanislav V. Zudin
Re[2]: Для чего нужна декларация operator new/delete в private секции класса?
От: s.d.s Россия  
Дата: 30.10.15 10:55
Оценка:
Здравствуйте, VTT, Вы писали:

VTT> еще стоит отметить, что автор забил на перегрузку new[] и delete[]


Не забил, они так же задекларированы в private, я просто в пример их не вынес, т.к. они проблем с линковкой не создают.


VTT> Если уж хочется что-то запрещать, то наверное лучше пометить как = delete.


Если добавить в Obj

private:
    friend class MyClass;
    void* operator new[](size_t) = delete;
    void operator delete[](void*) = delete;
    void* operator new(size_t, void*) = delete;
    void operator delete(void*, size_t) = delete;


то получаю в MyClass ошибку компиляции

    MyClass() : m_(new Obj) {  // <-- error C2280

error C2280: 'void Obj::operator delete(void *,size_t)': attempting to reference a deleted function


Это в MSVC 2015. В MSVC 2012 — все хорошо. GCC 5.2 тоже все переваривает без проблем.

Причем ссылка на operator delete(void *,size_t) есть в .obj но при нормальной работе этот оператор не используется (если логировать).
Re[3]: Для чего нужна декларация operator new/delete в private секции класса?
От: VTT http://vtt.to
Дата: 30.10.15 11:23
Оценка:
Может у вас какие дебаг оверлеи стоят или хитрые умные указатели?
А find all references ничего не находит?
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re: Для чего нужна декларация operator new/delete в private
От: s.d.s Россия  
Дата: 30.10.15 11:29
Оценка:
Для MSVC 2012

class Obj {
...
private:
    friend class MyClass;
    void* operator new(size_t, void*);
    void operator delete(void*, Obj_tag);
};

class MyClass {
...
};

#defined PN__

int main() {
#ifdef PN__
    char buf[1024] = { 0 };
    Obj * o1 = reinterpret_cast<Obj*>(buf);
    new (o1) Obj;
#endif
    MyClass o2;
}


Без определения PN__ компилируется без ошибок.
С PN__
error C2248: 'Obj::operator new': cannot access private member declared in class 'Obj'



Для MSVC 2015 такой код: без PN__ — не линкуется, с PN__ — выдает такую же ошибку.

Если изменить Obj

class Obj {
...
private:
    enum class Obj_tag : size_t {};
    friend class MyClass;
    void* operator new(size_t, void*);
    void operator delete(void*, Obj_tag);
};


то для MSVC 2015 получается такое же поведение как и для MSVC 2012.


Вопрос: а такое же оно в точности? (может я чего-то не учел)
Отредактировано 30.10.2015 11:30 s.d.s . Предыдущая версия .
Re[4]: Для чего нужна декларация operator new/delete в private секции класса?
От: s.d.s Россия  
Дата: 30.10.15 11:35
Оценка:
Здравствуйте, VTT, Вы писали:

VTT>Может у вас какие дебаг оверлеи стоят или хитрые умные указатели?

VTT>А find all references ничего не находит?

Насколько я понял из Breaking Changes in Visual C++ 2015,

void operator delete(void*, std::size_t);

объявленный внутри класса теперь перекрывает глобальный. И теперь MS рекомендует свой тип использовать в переопределении этого оператора.
Re[5]: Для чего нужна декларация operator new/delete в private секции класса?
От: VTT http://vtt.to
Дата: 30.10.15 11:45
Оценка:
Здравствуйте, s.d.s, Вы писали:

SDS>Здравствуйте, VTT, Вы писали:


VTT>>Может у вас какие дебаг оверлеи стоят или хитрые умные указатели?

VTT>>А find all references ничего не находит?

SDS>Насколько я понял из Breaking Changes in Visual C++ 2015,


SDS>
void operator delete(void*, std::size_t);

SDS>объявленный внутри класса теперь перекрывает глобальный. И теперь MS рекомендует свой тип использовать в переопределении этого оператора.

Как я понял, теперь
void operator delete(void*, std::size_t);

это обычный delete, а не placement delete
вот это поворот...
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.