Страницы

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

воскресенье, 22 декабря 2019 г.

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

#cpp #cpp11 #cpp14


Вопрос к гуру по стандартам 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;
}


Получается, что мы по сути создаем объект без инициализации полей, выполняя только
копирование объекта в самого себя, т.е. мусора на свое же место?
    


Ответы

Ответ 1



Такое объявление имеет неопределенное поведение. Рассмотрите программу 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-представления.

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

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