Инициализация объекта с помощью оператора 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