Инициализация объекта с помощью оператора new и без него

если у меня есть класс Rectangle

class Rectangle{

private:
    double width;
    double height;


public:
void    Set(double w , double l){
    width   = w;
    height  = l;
}
};

и я decleare объект такой:

Rectangle *Obj;

а затем попробуйте инициализировать его свойства:

Obj->Set(3,5);

компилятор показывает во время выполнения: The variable 'Obj' is being used without being initialized.

проблема может быть решена путем:

Rectangle *Obj=new Rectangle;

Я бы спросил о причине! И почему компилятор не показывает никаких ошибок во время компиляции?

7 ответов


Rectangle *Obj;

только указатель к объекту класса Rectangle. Определение указателя не резервирует никакой памяти для самого объекта, только для указателя. Таким образом, если вы получите доступ к указателю, вы, скорее всего, окажетесь по адресу в памяти, который даже не принадлежит вашему процессу. Однако компилятор не может знать, что указатель не инициализирован (ключевое слово здесь-aliasing), и поэтому не может вывести сообщение об ошибке.

в решение либо с помощью new как вы предложили, или объявить экземпляр Rectangle вот так:

Rectangle Obj;

который вызовет конструктор по умолчанию. Затем вы можете установить свои члены с помощью

Obj.Set(3, 5);

и я decleare объект такой:

Rectangle *Obj;

неправильно, это объявляется указатель, а не объект. Указатели должны быть инициализированы с помощью new или назначив им адрес существующего объекта.


МММ немного путаницы там:

компилятор показывает во время выполнения: переменная " Obj " используется без инициализации

это то, что вы бы назвали время компиляции. Просто уточняю жаргон.

кроме того, самым простым способом было бы

Rectangle Obj;
Obj.Set(3,5);

что достаточно для большинства сценариев, за исключением динамических распределений или полиморфных контейнеров:

std::vector<Shape*> v;
v.push_back(new Rectange());
v.back()->Set(3,5);

v.push_back(new Circle());
v.back()->Set(3,5);

//

хотя при использовании new вы должны помнить, чтобы delete как хорошо. Это может быть настоящий кошмар (в свете исключений тоже). Я предлагаю:

std::vector<std::shared_ptr<Shape*> > v;
v.push_back(std::make_shared<Rectange>());
v.back()->Set(3,5);

v.push_back(std::make_shared<Circle>());
v.back()->Set(3,5);

С Rectangle *Obj;, вы объявляете указатель на прямоугольник, но вы не сказали Obj в какой прямоугольник он должен указывать. Вы можете установить или создать экземпляр Obj позже к существующей Rectangle или только если требуется.

C++ - это все о давая вам точный контроль над вашей памятью и производительностью. Фактически, именно поэтому он используется в некоторых встроенных средах! Автоматическое создание экземпляра Obj ставит несколько "проблем"

  • когда мы освобождаем Obj?
  • кто освобождает Obj?
  • как насчет последствий для производительности создания Rectangle в куче?
  • это среда, в которой у нас достаточно ресурсов (память, процессор и т. д.), чтобы даже создать прямоугольник, особенно если он большой.
  • вы передаете адрес Obj где-то, а затем создать экземпляр во время выполнения с помощью какого-то сложного метода, который мы не можем статически анализировать?

что вы делаете не синтаксическая ошибка, что компиляторы будут выдавать ошибки на ... ошибки при компиляции. Анализатор (встроенный в Visual Studio 2010 professional) может предупредить, что используется неинициализированная переменная, хотя это необязательно и может потребоваться включить ее.


указатель без нового объявляет что-то без памяти .. Поэтому вам нужно использовать new с указателем. Однако Прямоугольник прямоугольник; defaultly будет выделять память .

чтобы проверить это, сделайте конструктор в классе Rectangle как,

void Rectangle
{
  cout<<"Rectangle Constructor";
}

затем, в main

Rectangle *rect; -->>O/P  -- "Nothing"
Rectangle rect2; -->>O/P  -- Rectangle Constructor
rect=new Rectangle; -->>O/P  -- Rectangle Constructor

почему компилятор не показывает никаких ошибок во время компиляции?

потому что это синтаксически правильно. Однако такие заявления приведут к неопределенное поведение умные компиляторы всегда будет выдавать предупреждение.

в g++ вы можете включить такое предупреждение компилятора в ошибки.


заявление прямоугольника *obj просто означает, что существует указатель, который будет указывать на переменную типа прямоугольник.

С помощью этого оператора вы просто создаете указатель не экземпляр прямоугольника объекта для использования этого указателя необходимо сохранить адрес переменной типа прямоугольника в указателе

два способа сделать это -

obj=new rectangle;  //variable is created in the stack storage

или

rectangle r;
obj =&r;     //variable is created in the heap storage