Страницы

Поиск по вопросам

четверг, 15 ноября 2018 г.

Конструирование без инициализации

Вопрос к гуру по стандартам C++ - что нынешний стандарт говорит о таком коде, вполне компилируемом и VC++, и GCC
#include #include
using namespace std;
class Test { public: Test() { cout << "Test()" << endl; } Test(int x):val_(x){ cout << "Test(" << x << ")" << endl; } Test(const Test& t):val_(t.val_) { cout << "Test(const Test& " << t.val_ << ")" << endl; } Test& operator = (const Test& t) { cout << "Test& operator = (const Test& " << t.val_ <<")" << endl; val_ = t.val_; return *this;} ~Test() { cout << "~Test()" << endl; } int val() const { return val_; } private: int val_ = 0; };
int main(int argc, const char * argv[]) { Test t = t; cout << t.val() << endl; }
Получается, что мы по сути создаем объект без инициализации полей, выполняя только копирование объекта в самого себя, т.е. мусора на свое же место?


Ответ

Такое объявление имеет неопределенное поведение.
Рассмотрите программу
struct A { A() : n(0), p(nullptr) {}
A(const A &a) : n(a.n), p(new int[n]) { for (size_t i = 0; i < n; i++) this->p[i] = a.p[i]; // std::copy(a.p, a.p + n, this->p); }
~A() { delete[] p; }
size_t n; int *p; };
int main() { A a = a; }
Так ни значение n , ни значение p не были инициализированы, а при этом вызывается конструктор копирования, копирующий объект в сам себя, то будет иметь место попытка выделения динамически памяти для массива неопределенного размера и обращение по адресу, который имеет неопределенное значение.
В стандарте C++ написано (12.7 Construction and destruction)
1 For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior.
В стандарте C, который является нормативным документом также для стандарта C++ также упоминается, что (6.2.6 Representations of types)
5 Certain object representations need not represent a value of the object type. If the stored value of an object has such a representation and is read by an lvalue expression that does ot have character type, the behavior is undefined. If such a representation is produced by a side effect that modifies all or any part of the object by an lvalue expression that does not have character type, the behavior is undefined.50) Such a representation is called a trap representation.
В приведенном примере выше, члены класса используются до вызова конструктора, так как они не были инициализированы конструктором, когда идет обращение к ним в конструкторе копирования, чтобы их значения использовать для инициализации создаваемых членов класса нового объекта. Кроме того эти члены класса могут иметь так-называемые trap-представления.

Комментариев нет:

Отправить комментарий