2013-11-07 3 views
0

Мой следующий класс имеет неопределенное поведение? Я думаю, что он четко определен, потому что я передаю аргументы конструктора по ссылке. я прав?Является ли класс contructor неопределенным поведением

class C 
{ 
    int* elem; 
    public: 
    C(int s[]) :elem(s){}; // Array arguments passed by reference, so its well defined? 
    void Print() 
    { 
     cout << elem[1] << endl; 
    } 
    ~C() 
    { 
     delete[] elem; 
    } 
}; 
int main() 
{ 
    C x(new int[2]{1,3}); 
    return 0; 
} 
+2

Если вы не 'delete [] elem;' в деструкторе, вы просачиваете память – billz

+1

Какое у вас поведение? Также как замечено выше, вы должны добавить деструктор – user2533527

+1

Где неопределенное поведение? – Montaldo

ответ

4

Он четко определен; вы создаете массив, передавая действительный указатель на конструктор (который принимает указатель, несмотря на то, что выглядит так, как будто он принимает массив), сохраняя этот указатель, а затем получая доступ к допустимому элементу массива через него.

Единственная проблема - утечка памяти - вы никогда не удаляете массив.

UPDATE Теперь вы добавили деструктор для удаления массива, класс очень опасен - если вы его скопируете, то обе копии попытаются удалить тот же массив. То, что будет, вызывает неопределенное поведение. Вам необходимо либо предотвратить копирование, либо реализовать его правильно, за Rule of Three. Вы также получите неопределенное поведение, если указатель не является массивом, созданным с помощью new[].

После того, как вы научились управлять ресурсами вручную, и насколько сложно получить все правильные сведения, вы обычно будете использовать класс библиотеки, чтобы сделать это за вас. В этом случае std::vector<int> будет идеальным. Выполнение этого иногда называют «Правилом нуля» (как упоминалось в комментариях), поскольку оно устраняет необходимость писать собственный деструктор или копировать/перемещать семантику вообще - все они происходят из класса (ов), который вы используете , который кто-то уже выполнил правильно.

+1

... вернее, Правило пяти, или, вернее, Правило Зеро. – Griwes

+0

Или если вы передадите ему указатель на все, что не является динамически распределенным массивом. – juanchopanza

+0

@Griwes: Действительно, правило Zero (использовать классы, которые уже имеют правильную семантику, а не их реализацию самостоятельно). На самом деле не существует правила пяти, по крайней мере, в отношении правильности; Переместить семантику - это то, о чем нужно думать об эффективности, а не необходимости в правильности. –

5

В вашем коде нет неопределенного поведения. Кроме того, вы не передаете по ссылке, вы передаете указатели по значению.

+0

Реали? Я думал, что в C++ массивы скрыты, переданные по ссылке. –

+0

Ссылки и указатели - это разные вещи. И массивы передаются значениями; тип - это тип указателя. – leemes

+1

@ VitoCarleone Передача массива с помощью простого имени, передает указатель на его первый элемент. Это часто описывается как «распад массивов указателям». Но в вашем случае это не то, что происходит в любом случае. Вы начинаете с указателя (оператор 'new' возвращает указатель.) Кроме того, аргумент вашего конструктора 'int s []' является просто синтаксическим сахаром для 'int * s'. Компилятор видит это как объявление указателя, а не массива. –

Смежные вопросы