Вопрос к гуру по стандартам C++ - что нынешний стандарт говорит о таком коде, вполне компилируемом и VC++, и GCC
#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-представления.
Комментариев нет:
Отправить комментарий