Първо, пример:
#include <cstddef>
#include <iostream>
struct S
{
S(int i) { if(i > 42) throw "up"; }
static void* operator new(std::size_t s, int i, double d, char c)
{
std::cout << "allocated with arguments: "
<<i<<", "<<d<<", "<<c<<std::endl;
return new char[s];
}
static void operator delete(void* p, int i, double d, char c)
{
std::cout << "deallocated with arguments: "
<<i<<", "<<d<<", "<<c<<std::endl;
delete[] (char*)p;
}
static void operator delete(void* p)
{
std::cout << "deallocated w/o arguments"<<std::endl;
delete[] (char*)p;
}
};
int main()
{
auto p0 = new(1, 2.0, '3') S(42);
S* p1 = nullptr;
try
{
p1 = new(4, 5.0, '6') S(43);
}catch(const char* msg)
{
std::cout << "exception: "<<msg<<std::endl;
}
delete p1;
delete p0;
}
Изход:
allocated with arguments: 1, 2, 3
allocated with arguments: 4, 5, 6
deallocated with arguments: 4, 5, 6
exception: up
deallocated w/o arguments
Каноничната дефиниция на оператор ново претоварване е void *operator new(std::size_t, heap h)
Не виждам как това е канонично, тъй като не е позволено: Добре, сега това е валидна форма за разположение на new
:)
[basic.stc.dynamic.allocation]/1
Функцията за разпределяне трябва да бъде функция член на клас или глобална функция; програма е неправилно оформена, ако функция за разпределение е декларирана в обхват на пространство от имена, различен от глобален обхват или декларирана като статична в глобален обхват. Върнатият тип трябва да бъде void*
. Първият параметър трябва да има тип std::size_t
. Първият параметър не трябва да има свързан аргумент по подразбиране. Стойността на първия параметър се тълкува като искания размер на разпределението.
[акцентът е мой]
Можете да претоварите функцията за разпределение, която да бъде извикана за формуляра за разположение на new
, вижте [expr.new] (не е изрично разрешено в [basic.stc.dynamic.allocation] за нешаблонни функции, но също така не е забранено). Разположението, дадено в new(placement)
, е обобщено тук до списък с изрази. Всеки израз в списъка с изрази за конкретен нов израз се предава като допълнителни аргументи към функцията за разпределение. Ако се извика функцията за освобождаване (напр. защото извиканият ctor хвърля изключение), същите аргументи плюс водещо void*
(върната стойност на функцията за разпределение) се предават на функцията за освобождаване.
[expr.new]/18 състояния:
Ако някоя част от инициализацията на обекта, описана по-горе, приключи чрез хвърляне на изключение, за обекта е получено съхранение и може да бъде намерена подходяща функция за освобождаване, функцията за освобождаване се извиква, за да освободи паметта, в която обектът е конструиран, след което изключението продължава да разпространява в контекста на новия израз. Ако не може да се намери недвусмислено съответстваща функция за освобождаване, разпространението на изключението не води до освобождаване на паметта на обекта. [Забележка: Това е подходящо, когато извиканата функция за разпределение не разпределя памет; в противен случай има вероятност да доведе до изтичане на памет. — крайна бележка ]
и /21
Ако нов израз извика функция за освобождаване, той предава стойността, върната от извикването на функцията за разпределение, като първи аргумент от тип void*
. Ако се извика функция за освобождаване на разположение, на нея се подават същите допълнителни аргументи, които са били предадени на функцията за разпределяне на разположение, т.е. същите аргументи като тези, посочени със синтаксиса за ново разположение.
и /20
Декларация на функция за освобождаване на разположение съвпада с декларацията на функция за разпределяне на разположение, ако има същия брой параметри и след трансформации на параметри всички типове параметри с изключение на първия са идентични. Всяка функция за освобождаване без разположение съответства на функция за разпределение без разположение. Ако търсенето намери една съвпадаща функция за освобождаване, тази функция ще бъде извикана; в противен случай няма да бъде извикана функция за освобождаване. Ако търсенето открие формата с два параметъра на обичайна функция за освобождаване и тази функция, считана за функция за освобождаване на разположение, би била избрана като съвпадение за функцията за разпределение, програмата е неправилно оформена. [Пример:
struct S {
// Placement allocation function:
static void* operator new(std::size_t, std::size_t);
// Usual (non-placement) deallocation function:
static void operator delete(void*, std::size_t);
};
S* p = new (0) S; // ill-formed: non-placement deallocation function matches
// placement allocation function
— краен пример ]
Връщане към [basic.stc.dynamic.deallocation]:
1 Функциите за освобождаване трябва да бъдат функции на клас или глобални функции; програма е неправилно оформена, ако функциите за освобождаване са декларирани в обхват на пространство от имена, различен от глобален обхват или декларирани като статични в глобален обхват.
2 Всяка функция за освобождаване трябва да върне void
и нейният първи параметър трябва да бъде void*
. Функцията за освобождаване може да има повече от един параметър.
person
dyp
schedule
30.10.2013
new
? Поставянето - ново разнообразие? - person John Dibling   schedule 30.10.2013