Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.55/11: Рейтинг темы: голосов - 11, средняя оценка - 4.55
2 / 2 / 0
Регистрация: 16.02.2011
Сообщений: 36
1

Почему создаются новые объекты?

19.02.2011, 01:03. Показов 2061. Ответов 21
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всем доброго времени суток!
Я не могу понять где создаются новые объекты
Есть у меня простенький класс
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class data 
{
    char* str;
public:
    data(): str("Hi")
    {}
    data(char* ch): str(ch)
    {}
    void setData(char* ch)
    {
        str = ch;
    }
    void printData()
    {
        cout << str << endl;
    }
    virtual ~data ()
    {
        cout << "data deleted\n";
    }
    data& operator= (data& v)
    {
        str = v.str;
        return *this;
    }
};
Обратите внимение на перегруженный оператор = . Если я возвращаю ссылку на data (как в коде), то при присваивании одго экземпляра класса другому, деструктор ничего не пише мне в консоль. Если я возвращаю просто data
C++
1
2
3
4
5
    data operator= (data& v)
    {
        str = v.str;
        return *this;
    }
то при присваивании в консоле дает о себе знать деструктор.
Зачем компилятор создет еще один экземпляр класса data что бы просто передать *this ?
Если кто понимает, то объясните пожалуйста.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
19.02.2011, 01:03
Ответы с готовыми решениями:

Создаются одинаковые объекты
Доброго времени суток. Начал изучать ООП и столкнулся с проблемой. Пишу класс работы с матрицами....

Классы: Не создаются объекты класса Apple
Includes.h #include &lt;stdlib.h&gt; #include &lt;gl\glut.h&gt; #include &lt;math.h&gt; #include&lt;stdio.h&gt;...

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

Написать программу, в которой создаются и разрушаются объекты, определенного пользователем класса
Цель: Получить практические навыки реализации классов на С ++. Основное содержание работы...

21
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
19.02.2011, 01:07 2
Потому что вы возвращаете не ссылку, а объект типа data. Чтобы вернуть объект, надо его скопировать в точку вызова, а потом удалить (тот, что был в функции). И компилятору пофиг, что это *this и что после выхода из функции он не уничтожится - вы ему сказали возвращать объект - он это и делает.
0
2 / 2 / 0
Регистрация: 16.02.2011
Сообщений: 36
19.02.2011, 09:50  [ТС] 3
Я не понял.
Какой удаляется объект?

Кстатиб такой код тоже вызывет деструктор 1 раз (при присваивании)
C++
1
2
3
4
5
    data operator= (data& v)
    {
        str = v.str;
        return data(str);
    }
0
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
19.02.2011, 10:16 4
OMGHero, вы для того, чтобы вернуть объект, создаёте временный, а именно data (str). При возврате объекта вызывается конструктор копии, который копирует этот временный объект в точку вызова, чтобы он стал результатом операции присваивания. Но в функции ведь осталась изначальная копия этого объекта, и при выходе из функции все локальные переменные должны быть уничтожены, следовательно, будет вызван деструктор для этого временного объекта, который был создан в функции как data (str).
0
2 / 2 / 0
Регистрация: 16.02.2011
Сообщений: 36
19.02.2011, 10:32  [ТС] 5
OMGHero, вы для того, чтобы вернуть объект, создаёте временный, а именно data (str). При возврате объекта вызывается конструктор копии, который копирует этот временный объект в точку вызова, чтобы он стал результатом операции присваивания. Но в функции ведь осталась изначальная копия этого объекта, и при выходе из функции все локальные переменные должны быть уничтожены, следовательно, будет вызван деструктор для этого временного объекта, который был создан в функции как data (str).
Да, этот механизм я понял. Функция создает один объект data (str), потом его уничтожает.
Не понятно что тут создается:
C++
1
2
3
4
5
6
 
 data operator= (data& v)
{
        str = v.str;
        return *this;
}
This не уничтожается. В обоих случаях при выполнении присваивания деконструктор вызывается только один раз. В превом случае понятно что саздается/удаляется (data(str)), во втором нет.
0
4773 / 2582 / 894
Регистрация: 29.11.2010
Сообщений: 5,590
19.02.2011, 10:35 6
Цитата Сообщение от OMGHero Посмотреть сообщение
Какой удаляется объект?
Временный. Который программа создаст для того, чтобы передать копию *this в
C++
1
2
3
4
5
* * * * data operator= (data& v)
* * * * {
* * * * * * * * str = v.str;
* * * * * * * * return data(str);
* * * * }
Вы же не ссылку возвращаете, и не указатель, а копию данных. Вот и создается копия класса data, которая удаляется после возвращения значения.

Кстати, некорректно работаете со строками. Вот пример, в котором никто никуда лишний раз не удаляется и содержимое класса Data передается по ссылке:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <cstdio>
#include <cstring>
 
class Data {
 public:
  Data() : string_(NULL) {}
  explicit Data(const char *string) : string_(NULL) {
    SetData(string);
  }
  ~Data() {
    printf("Debug: Calling destructor %d, '%s'.\n", (int)this, string_);
    delete string_;
  }
  void SetData(const char *string) {
    delete string_;
    string_ = strcpy(new char[strlen(string) + 1], string);
  }
  char *GetData() const { return string_; }
  Data &operator=(const Data &other) {
    if (this != &other)
      SetData(other.GetData());
    return *this;
  }
 private:
  char *string_;
};
 
int main(int argc, char *argv[]) {
  Data a("world!"), b("Hello"), c;
  c = a;
  a = b;
  b = c; // Меняем местами a и b;
  printf("%s %s\n", a.GetData(), b.GetData());
  return 0;
}
Цитата Сообщение от OMGHero Посмотреть сообщение
Не понятно что тут создается:
C++
1
2
3
4
5
data operator= (data& v)
{
        str = v.str;
        return *this; // возвращаем по значению, то бишь копию *this
}
Как что? Копия *this, конечно.
0
2 / 2 / 0
Регистрация: 16.02.2011
Сообщений: 36
19.02.2011, 11:00  [ТС] 7
lemegeton, а почему так копируете строки
C++
1
2
3
4
5
  
void SetData(const char *string) {
    delete string_;
    string_ = strcpy(new char[strlen(string) + 1], string);
 }
почему просто указатель не присвоить?

Вы же не ссылку возвращаете, и не указатель, а копию данных. Вот и создается копия класса data, которая удаляется после возвращения значения.
Тогда получается что в этом случае деструктор должен вызываться 2 раза
C++
1
2
3
4
5
        data operator= (data& v)
        {
                str = v.str;
                return data(str);
        }
один раз чтобы возвратить объект (возвращаем же копию данных). А второй раз - удалить data (str)
0
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
19.02.2011, 13:24 8
В случае
C++
1
2
3
4
5
data operator= (data& v)
{
        str = v.str;
        return *this;
}
будет создан временный объект, копия *this, который будет возвращён и удалён. В случае
C++
1
2
3
4
5
data operator= (data& v)
{
        str = v.str;
        return data (str);
}
вы вручную создаёте временный объект (data (str) - объект без имени), который будет скопирован в точку вызова, а потом удалён.

Добавлено через 3 минуты
Очень хочется получить сообщение 4 раза - пишите так:
C++
1
2
3
4
5
6
data operator= (data& v)
{
    str = v.str;
    data temporary_object(str);
    return temporary_object;
}
Здесь будет вызван деструктор для удаления temporary_object при выходе из функции (ещё до возвращения копии в точку вызова), а потом, после возврата копии будет ещё и вызван деструктор для удаления автоматически созданного временного объекта.
1
2 / 2 / 0
Регистрация: 16.02.2011
Сообщений: 36
19.02.2011, 13:32  [ТС] 9
Понял )

Добавлено через 7 минут
Цитата Сообщение от silent_1991 Посмотреть сообщение
Очень хочется получить сообщение 4 раза - пишите так:

data operator= (data& v)
{
str = v.str;
data temporary_object(str);
return temporary_object;
}
Здесь будет вызван деструктор для удаления temporary_object при выходе из функции (ещё до возвращения копии в точку вызова), а потом, после возврата копии будет ещё и вызван деструктор для удаления автоматически созданного временного объекта.
Этот код вызывает один раз деструктор. Проверьте.
0
4773 / 2582 / 894
Регистрация: 29.11.2010
Сообщений: 5,590
19.02.2011, 13:54 10
Цитата Сообщение от OMGHero Посмотреть сообщение
почему просто указатель не присвоить?
Ну, во-первых, такое присваивание строк deprecated, во-вторых, чтобы иметь копию значения, а не ссылку на него.
C++
1
2
3
4
5
6
  // предположим, есть char  *string, содержащий "123\0";
  char *a = string;
  // варианты выстрелить себе в ногу:
  srting[0] = '\0'; // изменив строку
  delete [] string; // или даже освободив память
  printf("%s\n", a); // ?????????
0
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
19.02.2011, 14:01 11
OMGHero, проверил. Вывод
Код
data deleted
data deleted
data deleted
data deleted
Добавлено через 5 минут
Вообще говоря полезно пробежаться по коду трассировщиком и воочию убедиться, что и где вызывается. Мне очень нравится трассировщик у MSVS2010, им и пользуюсь. Только что специально ради вас прогнал код - вызовы деструкторов:
при выходе из функции operator=, до возврата значения,
после возврата значения
при выходе из main (для удаления d1),
при выходе из main (для удаления d2)
В main у меня были созданы только два объекта, чтобы проверить присваивание.
1
2 / 2 / 0
Регистрация: 16.02.2011
Сообщений: 36
19.02.2011, 14:07  [ТС] 12
странно, у меня только один раз (без учета удаления объектов d1 и d2)
щас буду разбираться
0
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
19.02.2011, 14:19 13
Если интересно, вот код (вдруг вы чего у себя не поменяли или ещё что):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
 
using namespace std;
 
class data 
{
    char* str;
public:
    data(): str("Hi")
    {
    }
 
    data(char* ch): str(ch)
    {
    }
    
    data(const data &original):
    str(original.str)
    {
    }
 
    void setData(char* ch)
    {
        str = ch;
    }
    
    void printData()
    {
        cout << str << endl;
    }
    
    virtual ~data ()
    {
        cout << "data deleted\n";
    }
    
    data operator=(data& v)
    {
        str = v.str;
 
        data temporary_object(str);
 
        return temporary_object;
    }
};
 
int main()
{
    data d1("Hello");
    data d2("World");
 
    d1.printData();
    d2.printData();
 
    d1 = d2;
 
    d1.printData();
    d2.printData();
 
    return 0;
}
Вот вывод:
Код
Hello
World
data deleted
data deleted
World
World
data deleted
data deleted
Добавлено через 1 минуту
Ещё для наглядности добавил конструктор копии, чтобы при трассировке видеть, когда он вызывается, на работу деструкторов он, естественно, не влияет.
1
Эксперт С++
5043 / 2622 / 241
Регистрация: 07.10.2009
Сообщений: 4,310
Записей в блоге: 1
19.02.2011, 14:26 14
silent_1991, а я обычно смотрю примерно вот так
код и результат
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
 
class sample {
public:
    sample() {
        std::cout << "create of sample object: "    // comment
              << this << std::endl;         // object
    }
 
    sample(const sample& s) {
        std::cout << "create of sample object: "
              << this << std::endl;         // object
    }
 
    sample& operator = (const sample& s) {
        return *this;
    }
 
    ~sample() {
        std::cout << "destroy of sample object: "   // comment
              << this << std::endl;         // object
                  
    }
};
 
int main()
{
    sample a, c;
    sample b = a;
    
    c = b;
 
    return 0;
}
Код
create of sample object: 001BFE8F
create of sample object: 001BFE83
create of sample object: 001BFE77
destroy of sample object: 001BFE77
destroy of sample object: 001BFE83
destroy of sample object: 001BFE8F
. Видно какой объект создался и какой удалился.
2
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
19.02.2011, 14:32 15
fasked, не, старый добрый метод принтэфной отладки, конечно, никто не отменял))) Но мне как-то в последнее время удобно пользоваться трассировщиком, тем более что мелкомягкие в этот раз действительно на славу постарались)))
0
2 / 2 / 0
Регистрация: 16.02.2011
Сообщений: 36
19.02.2011, 14:33  [ТС] 16
silent_1991, не могли бы вы дать ссылку на мануал где этот трассировщик в visual studio. я его до этого никогда не использовал. В гугле Ip трассировщики вылазают
0
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
19.02.2011, 14:40 17
OMGHero, вы просто жмёте F10 или F11 и пошагово прогоняете программу. Внизу появится окно трассировки с отображением значений всех переменных, а маркер будет указывать на строку, которая выполняется. При этом F10 - шаг с обходом (например, пропуск функции, т.е. функция фактически будет вызвана и выполнена, но отображено это не будет и произойдёт переход на следующую строку), а F11 - шаг с заходом - подробная трассировка, будет выполнен заход всюду, куда только можно.
0
2 / 2 / 0
Регистрация: 16.02.2011
Сообщений: 36
19.02.2011, 14:47  [ТС] 18
Цитата Сообщение от silent_1991 Посмотреть сообщение
вы просто жмёте F10 или F11 и пошагово прогоняете программу. Внизу появится окно трассировки с отображением значений всех переменных, а маркер будет указывать на строку, которая выполняется. При этом F10 - шаг с обходом (например, пропуск функции, т.е. функция фактически будет вызвана и выполнена, но отображено это не будет и произойдёт переход на следующую строку), а F11 - шаг с заходом - подробная трассировка, будет выполнен заход всюду, куда только можно.
а как увидеть какие объекты создаются ? например как увидеть какой объект создается при возврате функцией *this ?
0
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
19.02.2011, 14:52 19
OMGHero, ну это ведь временный объект, имени у него нет. Потому он не будет отображаться в списке переменных. Но по-моему и так понятно, что это тот самый временный объект, который возвращается в точку вызова (потому что он удаляется после вызова return, но до выхода из функции).
0
2 / 2 / 0
Регистрация: 16.02.2011
Сообщений: 36
19.02.2011, 15:00  [ТС] 20
silent_1991, Вот результат вашего кода у меня. Наверное разница в компиляторах, может мой что-то соптимизировал и не стал создавать еще один объект. Пользуюсь Visual Studio 2010

Код
Hello
World
data deleted
World
World
data deleted
data deleted
0
19.02.2011, 15:00
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
19.02.2011, 15:00
Помогаю со студенческими работами здесь

Не создаются новые потоки при распараллеливании цикла for (работает только один поток - главный)
Доброго времени суток, ребята! Пишу код по распараллеливанию умножения матриц. Всё вроде...

Написать программу, в которой создаются и уничтожаются объекты класса "Library", определенного пользователем
Здравствуйте. Помогите пожалуйста. Написать программу, в которой создаются и уничтожаются...

Почему при программировании C++/Win32 создаются элементы старого вида?
И снова всем здравствуйте!!! Я продолжаю грызть гранит программирования на C++ В общем проблема...

В винде создаются новые сети
Здравствуйте!) Каждый раз,когда вставляю телефон через USB, и использую в качестве модема,то...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru