Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Глюк VS или недопонимание?  (Прочитано 16388 раз)
0 Пользователей и 7 Гостей смотрят эту тему.
Migmile
Помогающий

ru
Offline Offline

« : 22-10-2003 07:53 » 

Странный bag? в компиляторе С++ VS.NET
Проблема с вызовами конструкторов и деструкторов.
class A
{
 public:
 int *ptr;
 A(int a) {ptr=new int[20]; cout<<"A ";}
 ~A(){cout<<"~A ";  delete[] ptr;}
// A(const A& a) {ptr=new int[20]; cout<<"copy constr";}
};

class B
{
 public:
 A *a;
 B(A a){}
};


B b(A(5));
Сначала создается неименованный объект А(5). Затем делается его точная копия
во временную переменную, которая и передается в конструктор В. На самом деле
вроде бы и имеет право (хотя не совсем уверен:) Смотрим далее. При выходе
из конструктора В вызывается деструктор временной копии! (а ведь конструктор
ее не вызывался!) Затем, уже после вызова конструктора В вызывается деструктор
для неименованного объекта А(5). На самом деле ничего противозаконного.
Но так как внутри класса А распределяется память двойной вызов деструктора
приводит к ошибочному повторному освобождению ptr. Классика жанра:)
Делаем, как и полагается в приличных программах, конструктор копии
(закоментарен в пред. примере). И что же присходит? - совсем не то, что
ожидается! Конструктор копии НЕ вызывается, временная переменная для передачи
объекта А(5) в конструктор В НЕ СОЗДАЕТСЯ и деструктор вызывается только
ОДИН РАЗ! Я так и не понял в чем тут хохма.
Кстати сказать, компилятер Borland C++ 5.5 (от Builder) вообще с самого начала
не создавал временной переменной и сразу передавал созданный A(5) в В().
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #1 : 22-10-2003 08:37 » 

virtual деструктор - помогло!
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #2 : 22-10-2003 11:14 » 

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

А птичку нашу прошу не обижать!!!
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #3 : 22-10-2003 12:11 » 

Дык я их такими и делаю Ага.
Прикол заключался у меня на 6ой версии в том, что я  при установке стандартного конструктора не мог поставить break point  в него  Я шокирован! . Он постоянно перепрыгивал вниз. Вот это ЖУК!!! Кстати тоже интересно как на других С++ ах
это обрабатывается?
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Serega
Гость
« Ответ #4 : 22-10-2003 12:22 » 

Гром, у кого это принято делать виртуальными деструкторы Не понял
Если не используется полиморфизм то для чего создавать таблицу Не понял

Migmile, если хочешь узнать побольше о том что происходит попроси Грома выложить книгу Efficient C++, там хорошо рассматриваются способы передачи и возврата параметров, безымянные переменные и многое другое
Записан
Serega
Гость
« Ответ #5 : 22-10-2003 12:49 » 

Если внутри есть указатели,
Во-первых: ОБЯЗАТЕЛЬНО должен быть копирующий конструктор (конечно можно постараться гарантировать не передавать обьекты данного типа по значению, но это опять же делается с помощью сокрытия копирующего конструктора)
Во-вторых: также ОБЯЗАТЕЛЬНО должен быть деструктор т.к. деструктор встроенного указателя ничего не делает (виртуальность нужна только в случае полиморфизма)

А по поводу передачи параметров
Код:
#include <iostream>
#include <memory>

using namespace std;

class A
{
int* ptr;
public:
A(int a) : ptr(new int[20]) | cout << "ctor A" << endl; "
A(const A& a) : ptr(new int[20]) | cout << "copy ctor A" << endl; }
~A() | cout << "~A" << endl; delete[] ptr; "
};

class B
{
auto_ptr<A> myA;
public:
B(A a) : myA(new A(a)) {}
};

int main(int argc, char* argv[])
{
B b(A(5));
return 0;
}
в этом коде конструктор и деструктор А вызываются два раза, как и положено
несложно догадаться что в таком коде
Код:
class B 
{
public:
B(A a)  {}
};
конструктор копий вообще не будет вызван
« Последнее редактирование: 20-11-2007 18:05 от Алексей1153++ » Записан
Migmile
Помогающий

ru
Offline Offline

« Ответ #6 : 22-10-2003 13:06 » 

Serega, полностью согласен, за исключением последнего замечания про конструктор копий. Если имеется в виду, что в примере пустой конструктор В, то на самом деле это не играет рояли. Вопрос то в том, почему при создании конструктора копии у А в В передается АДРЕС временного объекта, а не его копия!!!
Записан
Serega
Гость
« Ответ #7 : 22-10-2003 13:24 » 

На это тебе даст ответ Efficient C++
Записан
Migmile
Помогающий

ru
Offline Offline

« Ответ #8 : 22-10-2003 14:47 » new

Serega, а кто автор?
Записан
Serega
Гость
« Ответ #9 : 22-10-2003 14:55 » 

Dov Bulka и David Mayhew
Записан
Migmile
Помогающий

ru
Offline Offline

« Ответ #10 : 22-10-2003 15:30 » 

Serega, Уже смотрю Улыбаюсь
Но в главе 5( temporaries) ничего не нашел, про создание временных переменных при передаче параметра по значению и так ясно.
Записан
Serega
Гость
« Ответ #11 : 22-10-2003 15:35 » 

Смотри 4-ю (return value optimization)
Записан
Migmile
Помогающий

ru
Offline Offline

« Ответ #12 : 22-10-2003 16:19 » 

А как связаны RVO  и изменение поведения компилятора при включении НЕИСПОЛЬЗУЕМОЙ функции (конструктор копии - после раскоментирования все равно не используется!)Не понял
Пока вопрос открыт Улыбаюсь
Записан
NetRaider
Гость
« Ответ #13 : 23-10-2003 02:14 » 

Цитата

Странный bag? в компиляторе С++ VS.NET
Проблема с вызовами конструкторов и деструкторов.
class A
{
public:
int *ptr;
A(int a) {ptr=new int[20]; cout<<"A ";}
~A(){cout<<"~A "; delete[] ptr;}
// A(const A& a) {ptr=new int[20]; cout<<"copy constr";}
};

class B
{
public:
A *a;
B(A a){}
};

B b(A(5));
Сначала создается неименованный объект А(5). Затем делается его точная копия
во временную переменную, которая и передается в конструктор В. На самом деле
вроде бы и имеет право (хотя не совсем уверен Смотрим далее. При выходе
из конструктора В вызывается деструктор временной копии! (а ведь конструктор
ее не вызывался!) Затем, уже после вызова конструктора В вызывается деструктор
для неименованного объекта А(5). На самом деле ничего противозаконного.
Но так как внутри класса А распределяется память двойной вызов деструктора
приводит к ошибочному повторному освобождению ptr. Классика жанра
Делаем, как и полагается в приличных программах, конструктор копии
(закоментарен в пред. примере). И что же присходит? - совсем не то, что
ожидается! Конструктор копии НЕ вызывается, временная переменная для передачи
объекта А(5) в конструктор В НЕ СОЗДАЕТСЯ и деструктор вызывается только
ОДИН РАЗ! Я так и не понял в чем тут хохма.
Кстати сказать, компилятер Borland C++ 5.5 (от Builder) вообще с самого начала
не создавал временной переменной и сразу передавал созданный A(5) в В().


В выражении "B b(A(5));" создается временный безымянный объект типа A. Так как этот объект не имеет имени, вместо него будет использована ссылка(константная). Но, конструктор "B::B(A a)" в качестве параметра принимает объект, а не ссылку на него. Из-за этого будет вызван конструктор копирования для создания объекта, который будет передан конструктору B::B(A a). Если в классе A явно не определен copy ctor, то вместо него будет вызван конструктор копирования, определенный компилятором, который будет почленно копировать объекты(но не будет выделять память, которая удаляется в деструкторе). Хорошо, определим copy ctor...

Цитата


И что же присходит? - совсем не то, что
ожидается! Конструктор копии НЕ вызывается, временная переменная для передачи
объекта А(5) в конструктор В НЕ СОЗДАЕТСЯ и деструктор вызывается только
ОДИН РАЗ!



Фокус в том, Стандарт позволяет компилятору проводить оптимизацию многочисленных вызовов конструкторов. Видимо, наличие явно определенного конструктора копирования(как и виртуально деструктора) говорит компилятору о возможной оптимизации.
Записан
Migmile
Помогающий

ru
Offline Offline

« Ответ #14 : 23-10-2003 10:20 » 

Цитата: NetRaider
Фокус в том, Стандарт позволяет компилятору проводить оптимизацию многочисленных вызовов конструкторов. Видимо, наличие явно определенного конструктора копирования(как и виртуально деструктора) говорит компилятору о возможной оптимизации.
- это единственное, кажущееся разумным, допущение Улыбаюсь
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines