Инициализация объекта с новым оператором и без него - PullRequest
22 голосов
/ 23 ноября 2011

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

class Rectangle{

private:
    double width;
    double height;


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

и я объявляю объект таким:

Rectangle *Obj;

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

Obj->Set(3,5);

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

Проблема может быть решена с помощью:

Rectangle *Obj=new Rectangle;

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

Ответы [ 7 ]

24 голосов
/ 23 ноября 2011
Rectangle *Obj;

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

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

Rectangle Obj;

, который будет вызывать конструктор по умолчанию. Затем вы можете установить своих членов, используя

Obj.Set(3, 5);
8 голосов
/ 23 ноября 2011

и я объявляю объект таким:

Rectangle *Obj;

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

4 голосов
/ 23 ноября 2011

Ммм, немного смущения:

компилятор показывает во время выполнения: переменная '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);
3 голосов
/ 27 сентября 2013

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

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

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

тогда, в основном

Rectangle *rect; -->>O/P  -- "Nothing"
Rectangle rect2; -->>O/P  -- Rectangle Constructor
rect=new Rectangle; -->>O/P  -- Rectangle Constructor
3 голосов
/ 23 ноября 2011

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

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

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

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

2 голосов
/ 23 ноября 2011

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

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

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

0 голосов
/ 12 июня 2016

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

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

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

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

или

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