помогите прояснить неясные моменты касаемо следующего кода:
#include <iostream>
#include <cstddef>
using namespace std;
class myException
{
};
class CTest
{
int i;
public:
CTest()
{
throw myException(); //1.
printf("CTest object created ok!\n");
}
~CTest()
{
printf("CTest object destroyed ok!\n");
}
void *operator new(size_t size) throw (std::bad_alloc)
{
printf("allocating a CTest object...");
//throw std::bad_alloc(); //2.void * res = NULL;
res = ::operator new(size);
if ( res )
printf("%p size %d... \n", res, (int) size);
return res;
}
void operator delete (void *p, size_t size)
{
printf("deallocating a CTest object %p size %d\n", p, (int)size);
::operator delete(p);
}
};
int main()
{
CTest *pCTest = NULL;
try{
pCTest = new CTest();
}
catch ( myException &)
{
printf("myException caught!!\n");
printf("pCTest %p\n", (void*)pCTest);
return -1;
}
catch ( std::bad_alloc )
{
printf("std::bad_alloc caught!!\n");
printf("unable to allocate CTest object\n");
}
printf("normal program flow\n");
printf("pCTest %p\n", (void*)pCTest);
delete pCTest;
return 0;
}
вариант, если строка //1 раскомментена, а строка //2 закомментена:
почему при срабатывании исключения в конструкторе класса далее неявно вызывается operator delete. как С++ система узнает, что несмотря на то, что создание объекта не произошло, память, выделенную под него явно посредством operator new, следует удалить, и это происходит автоматически сразу же после срабатывания исключения в конструкторе?
вариант, если строка //1 закомментена, а строка //2 раскомментена
почему при возбуждении исключения std::bad_alloc при выделении памяти под объект класса далее в ф-ции main не происходит вызов operator delete для этого класса несмотря на то, что операция удаления delete pCTest; прописана явно? в стандарте где-то оговорено, что при удалении NULL поинтера operator delete не будет вызываться?
шыбко не пинайте, это мое первое сообщение на этом форуме.
спасибо.
Здравствуйте, varnie, Вы писали:
V>почему при срабатывании исключения в конструкторе класса далее неявно вызывается operator delete. как С++ система узнает, что несмотря на то, что создание объекта не произошло, память, выделенную под него явно посредством operator new, следует удалить, и это происходит автоматически сразу же после срабатывания исключения в конструкторе?
Потому что автоматически при вызове конструктора вставляется отлов исключений, и если исключение вылетело, зовется operator delete и исключение перевыбрасывается.
V>почему при возбуждении исключения std::bad_alloc при выделении памяти под объект класса далее в ф-ции main не происходит вызов operator delete для этого класса несмотря на то, что операция удаления delete pCTest; прописана явно? в стандарте где-то оговорено, что при удалении NULL поинтера operator delete не будет вызываться?
Здравствуйте, varnie, Вы писали:
V>вариант, если строка //1 раскомментена, а строка //2 закомментена:
V>почему при срабатывании исключения в конструкторе класса далее неявно вызывается operator delete.
По определению. Это требование стандарта языка С++.
15.2/2
An object that is partially constructed or partially destroyed will have destructors executed for all of its
fully constructed subobjects, that is, for subobjects for which the constructor has completed execution and
the destructor has not yet begun execution. Should a constructor for an element of an automatic array
throw an exception, only the constructed elements of that array will be destroyed. If the object or array was
allocated in a new-expression, the matching deallocation function (3.7.3.2, 5.3.4, 12.5), if any, is called to
free the storage occupied by the object.
V>как С++ система узнает, что несмотря на то, что создание объекта не произошло, память, выделенную под него явно посредством operator new, следует удалить, и это происходит автоматически сразу же после срабатывания исключения в конструкторе?
Это детали реализации — они не должны тебя волновать.
V>вариант, если строка //1 закомментена, а строка //2 раскомментена
V>почему при возбуждении исключения std::bad_alloc при выделении памяти под объект класса далее в ф-ции main не происходит вызов operator delete для этого класса несмотря на то, что операция удаления delete pCTest; прописана явно?
Явно прописано не что иное, как delete-expression, что не то же самое, что и deallocation function 'operator delete'.
V>в стандарте где-то оговорено, что при удалении NULL поинтера operator delete не будет вызываться?
Да:
5.3.5/2
...
In either alternative, if the value of the operand of delete is the null pointer the operation
has no effect.
...
Любите книгу — источник знаний (с) М.Горький
Re: вопрос касаемо exceptions и operator new/delete
Здравствуйте, varnie, Вы писали:
V>вариант, если строка //1 раскомментена, а строка //2 закомментена:
V>почему при срабатывании исключения в конструкторе класса далее неявно вызывается operator delete. как С++ система узнает, что несмотря на то, что создание объекта не произошло, память, выделенную под него явно посредством operator new, следует удалить, и это происходит автоматически сразу же после срабатывания исключения в конструкторе?
V>вариант, если строка //1 закомментена, а строка //2 раскомментена
V>почему при возбуждении исключения std::bad_alloc при выделении памяти под объект класса далее в ф-ции main не происходит вызов operator delete для этого класса несмотря на то, что операция удаления delete pCTest; прописана явно? в стандарте где-то оговорено, что при удалении NULL поинтера operator delete не будет вызываться?
Выражение new реализуется компилятором примерно так:
T* new (alloc_args) T(ctor_args)
{
// сперва пытаемся выделить память...
T* ptr = (T*)T::operator new(sizeof(T), alloc_args); // или глобальный оператор, если он не перегружен
/*1*/if(!ptr)
return 0;
try
{
// затем конструируем объект в этой памяти
ptr->ctor(ctor_args);
}
catch(...)
{
// в случае неудачи - освобождаем память
T::operator delete(ptr, alloc_argc);
// и пробрасываем исключениеthrow;
}
return ptr;
}
Таким образом, если исключение возникло в операторе new, то, во-первых, память не выделена — и освобождать нечего, а во-вторых, мы вылетим ещё до точки /*1*/.
А если исключение произошло в конструкторе, то объект, понятное дело, не создан (деструктор не вызывается, кстати), и нужно освободить память соответствующим оператором delete.
Именно поэтому для placement new существуют тривиальный operator new(size_t,void*) и парный к нему тривиальный operator delete(void*,void*).
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[2]: вопрос касаемо exceptions и operator new/delete
Здравствуйте, jazzer, Вы писали:
V>> в стандарте где-то оговорено, что при удалении NULL поинтера operator delete не будет вызываться?
J>Да, прописано.
Собственно, вопрос о том, что именно по этому поводу прописано в стандарте, обсуждается уже лет пять. По последним данным, реализация имеет право вызывать operator delete при использовании null pointer value в delete-expression, но не обязана делать это (See DR#348).
Re[3]: вопрос касаемо exceptions и operator new/delete
Здравствуйте, elcste, Вы писали:
E>Здравствуйте, jazzer, Вы писали:
V>>> в стандарте где-то оговорено, что при удалении NULL поинтера operator delete не будет вызываться?
J>>Да, прописано.
E>Собственно, вопрос о том, что именно по этому поводу прописано в стандарте, обсуждается уже лет пять. По последним данным, реализация имеет право вызывать operator delete при использовании null pointer value в delete-expression, но не обязана делать это (See DR#348).
Спасибо, было весело почитать
Сначала аргументация типа "Standard doesn't specify term "has no effect".", а потом в предложении по изменениям "The value of the first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect"
Здравствуйте, jazzer, Вы писали:
E>>Собственно, вопрос о том, что именно по этому поводу прописано в стандарте, обсуждается уже лет пять. По последним данным, реализация имеет право вызывать operator delete при использовании null pointer value в delete-expression, но не обязана делать это (See DR#348).
J>Спасибо, было весело почитать J>Сначала аргументация типа "Standard doesn't specify term "has no effect".", а потом в предложении по изменениям "The value of the first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect"
Да, далек стандарт от совершенства, очень далек. Новые формулировки хотя бы отвечают на практический вопрос, что будет с пользовательским operator delete. Уже приятно. Но, откровенно говоря, лично я предпочел бы стандарт в виде формального математического описания, а не в human readable форме.