Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Red Planet
49 / 10 / 2
Регистрация: 20.09.2009
Сообщений: 263
#1

"Повторная" инициализация объекта - C++

12.02.2012, 21:18. Просмотров 677. Ответов 7
Метки нет (Все метки)

C++
1
2
3
4
5
class A {
    int x, y;
    public A() { x = y = 100; }
    public A(int xx, int yy) { x = xx; y = yy;}
};
C++
1
2
A a1 = A();
a1 = A(6, 4);
Меня интересует, что произойдет со значениями по умолчанию, которыми в первый раз был проинициализирован объект после инициализации вторым конструктором. Они останутся висеть где-то в памяти?

 Комментарий модератора 
Вроде не первый день на форуме. Зачем в чужую тему влезли?
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
12.02.2012, 21:18
Здравствуйте! Я подобрал для вас темы с ответами на вопрос "Повторная" инициализация объекта (C++):

Для агрегатного объекта требуется инициализация с использованием "{.}" - C++
Помогите.. как засунуть \\" + string(z) + "\\ правельно unsigned long Size = 256; char *z = new char; ...

Error C2440: инициализация: невозможно преобразовать "void *" в "listnode *". подскажите, что можно сделать? - C++
#include <iostream> struct listnode { char *data; int value; struct listnode *next; }; struct listnode...

Warning C4244: инициализация: преобразование "__int64" в "int", возможна потеря данных - C++
Что за предупреждение вылезает? Как исправить? (16 строка): warning C4244: инициализация: преобразование "__int64" в "int", возможна...

В зависимости от времени года "весна", "лето", "осень", "зима" определить погоду "тепло", "жарко", "холодно", "очень холодно" - C++
В зависимости от времени года "весна", "лето", "осень", "зима" определить погоду "тепло", "жарко", "холодно", "очень холодно". Я так...

Создание объекта класса сразу после его описания (между "}" и ";") - C++
Пишу проект с дюжиной хедеров и десятком cpp-шников. Мне нужны пара объектов класса А, которые должны существовать на протяжении всей...

Перегрузить операторы "=", "+=" так, чтобы производилось сложение строки и объекта - C++
помогите ,пожалуйста вот задание:Реализовать класс String для работы со строками символов. Перегрузить операторы =, += так, чтобы...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
silent_1991
Эксперт С++
4964 / 3040 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
12.02.2012, 21:41 #2
Red Planet, нет. В эту же память запишется новый объект.
1
Red Planet
49 / 10 / 2
Регистрация: 20.09.2009
Сообщений: 263
19.02.2012, 14:12  [ТС] #3
Очень удивился, когда увидел, что деструктор вызывается после вызова второго конструктора, а не до. Ведь логичнее было бы разрушить старый объект перед созданием нового, а здесь получается, что сначала имеем один объект, потом реинициализиреум его поля, потом вызываем деструктор, потом работаем с новымыми значениеями полей. Почему в таком странном порядке идет работа? Ладно еще, если не используем динамическую память (хотя зачем нам деструктор без нее?), - тогда внешне все в порядке. А вот если попробовать вызвать a1.show() после второй инициализации, то сначала вместо значения, хранящегося в p получим какое-то произвольное число, а потом вылетит исключение.

Ниже вывод программы и код.

Вывод.

Created
10 10
Other values
Created
Deleted
100 100
Для продолжения нажмите любую клавишу . . .
Код без указателя.

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
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
class A {
    int x, y;
    public: A() { x = y = -1; cout << "Created default" << endl; }
            A(int xx, int yy) { x = xx; y = yy; cout << "Created" << endl; }
            ~A() { cout << "Deleted" << endl; }
            void show() { std::cout << x << " " << y << endl; } 
 
};
 
 
int _tmain(int argc, _TCHAR* argv[]) {
    A a1 = A(10, 10);
    a1.show();
    cout << "Other values" << endl;
    a1 = A(100, 100);
    a1.show();
    system("pause");
    return 0;
}
Код с указателем.

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
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
class A {
    int x, y, *p;
    public: A() { x = y = -1; p = new int(100); cout << "Created default" << endl; }
            A(int xx, int yy) { x = xx; y = yy; p = new int(100); cout << "Created" << endl; }
            ~A() { delete p; cout << "Deleted" << endl; }
            void show() { std::cout << x << " " << y << " " << *p << endl; } 
 
};
 
 
int _tmain(int argc, _TCHAR* argv[]) {
    A a1 = A(10, 10);
    a1.show();
    cout << "Other values" << endl;
    a1 = A(100, 100);
    a1.show();
    system("pause");
    return 0;
}
0
silent_1991
Эксперт С++
4964 / 3040 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
19.02.2012, 15:19 #4
Red Planet, потому что вторая "инициализация" - не инициализация. Есть динамический захват ресурсов в конструкторе, святое правило - написать конструктор копии и оператор присваивания.
Ну а первое удаление - это не удаление старого объекта, как вы думаете, а удаление временного объекта, созданного в строке a1 = A(100, 100);, которым неверно инициализируется старый. Именно из-за этого удаления и использования оператора присваивания по умолчанию происходил баг с повторным освобождением памяти.
0
DU
1483 / 1059 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
19.02.2012, 15:30 #5
Created - создался объект а1
10 10 // печать объекта а1
Other values
Created - создался временный объект типа A, который передается в оператор =
.. тут в промежутке из этого временного объекта копируются данные в объект a1
Deleted - тут этот временный объект умирает

100 100 // печать объекта а1
Для продолжения нажмите любую клавишу . . .

Можете в трейсы добавить печать значения указателя this, тогда будет видно какие объекты создаются и умирают.
1
silent_1991
Эксперт С++
4964 / 3040 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
19.02.2012, 15:38 #6
Пояснения:
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
int main()
{
    // Здесь, по идее, происходит два действия: сначала конструктор с
    // параметрами конструирует временный объект, который затем с помощью
    // конструктора копии копируется в объект a1. Доказать это просто -
    // достаточно поместить конструктор копии в приватную область, и код не
    // скомпилируется. Однако все эти промежуточные действия соверщенно не
    // нужны, и компилятор выкидывает их, оставляя конструирование объекта a1
    // сразу с помощью конструктора с параметрами, т.е. код становится
    // эквивалентен A a1(10, 10);
    A a1 = A(10, 10); // Вывод "Created"
    
    a1.show(); // Вывод "10 10 100"
    cout << "Other values" << endl;
    
    // Следующую строку можно разделить на три:
        // Воспринимаем __tmp как временный объект.
        // A __tmp(100, 100); // Вывод "Created"
        
        // Копируем временный объект в a1
        // a1.operator=(__tmp);
        
        // Воспринимаем эту строку как полное удаление временного
        // объекта, а не простой вызов деструктора. Сути это, однако,
        // не меняет, нам было важно то, что для временного объекта
        // вызвался деструктор.
        // __tmp.~A(); // Вывод "Deleted"
    // Благодаря тому, что оператор присваивания не был реализован,
    // использовался предоставляемый по умолчанию оператор присваивания,
    // побайтно копирующий данные из одного объекта в другой. Т.е. был
    // скопирован сам указатель из __tmp, а не его значение. Затем, после
    // копирования __tmp удаляется и, соответственно, память, на которую теперь
    // указывает как __tmp.p, так и a1.p, становится невалидной. Ну а дальше
    // всё ясно, при обращении к невалидной памяти получаем дулю.
    a1 = A(100, 100); // Вывод "Created"; Вывод "Deleted"
    
    a1.show(); // Вывод "100 100 абырвалг"
    
    // Вывод " Deleted"
    return 0;
}
1
Red Planet
49 / 10 / 2
Регистрация: 20.09.2009
Сообщений: 263
25.02.2012, 21:57  [ТС] #7
Я не знал о временном объекте, который создается перед инициализацией и присваиванием. Действительно, написание операторов все логично объясняет. Операторы взяты со Страуструпа.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
A::A(const A &right) {
    p = new A;
    *p = *(right.p);
    x = right.x;
    y = right.y;
}
 
A& A::operator =(const A &right) {
    if (&right != this) {
        delete p;
        p = new int;
        *p = *(right.p);
        x = right.x;
        y = right.y;
    }
    return *this;
}
Надо будет только поразбираться с возвращаемыми значениями A& и A. Там у него не одна страница про это написано, но это завтра.

Следующее. Что скажете насчет такого кода? Все ли правильно?

Смысл такой. При сложении двух объектов сумма должна "знать" правого операнда. Поэтому заведен указатель *p, который проявляется только при сложении, в остальных случаях он никуда не указывает. Приведенный код работает, однако меня смущает то, что два указателя ссылаются на одно и тоже значение. См. оператор сложения, в нем строка

C++
1
p = right.p;
При применении

C++
1
2
A a4 = a3;
A a5 = a3;
еще два объекта, у которых есть указатель, ссылающихся на тот же объект - правый операнд того самого сложения.

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <vcl>
#include <iostream>
#include <list>
#pragma hdrstop
 
using namespace std;
 
class A {
    int x, y; A *p;
 
    public:
        A(int xx, int yy, A *p);
 
        A(int xx = -1, int yy = -1) :
            x(xx), y(yy), p(0) {}
 
        A& operator =(const A&);
        A operator +(const A&);
        bool operator ==(const A&);
        void show();
 
        A get_p_value() const { return *p; }
};
 
void A::show() {
    if (p != 0)
        cout << x << " " << y << " Right was: " << p->x << " " << p->y << endl;
    else
        cout << x << " " << y << " Right was: unknown" << endl;
}
 
A::A(int xx, int yy, A *pp) {
    x = xx;
    y = yy;
    p = pp;
}
 
A& A::operator =(const A& right) {
    if (this != &right) {
        p = right.p;
        x = right.x;
        y = right.y;
    }
    return *this;
}
 
A A::operator +(const A &right) {
    return A(x + right.x, y + right.y, const_cast<A*>(&right));
}
 
bool A::operator ==(const A &right) {
    return x == right.x && y == right.y && p == right.p;
}
 
#pragma argsused // No warning if function args are not in use.
// But there is no warning while compiling project. Why?
int _tmain(int argc, _TCHAR* argv[]) {
    list<A> lst = list<A>();
    A a1 = A(10, 10), a2(5, 7), a3;
    lst.push_back(a1);
    lst.push_back(a2);
 
    cout << "List before processing" << endl;
    for (list<A>::iterator it = lst.begin(); it != lst.end(); it++)
        it->show();
 
    a3 = a1 + a2;
    lst.remove(a3.get_p_value());
 
    cout << endl << "List after processing" << endl;
    for (list<A>::iterator it = lst.begin(); it != lst.end(); it++)
        it->show();
 
    system("pause");
}
0
silent_1991
Эксперт С++
4964 / 3040 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
25.02.2012, 23:26 #8
Red Planet, ну так не присваивайте указатели в операторе присваивания))
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
25.02.2012, 23:26
Привет! Вот еще темы с ответами:

Что делать с ошибкой: C2440: инициализация: невозможно преобразовать "int **" в "int *" - C++
Задание, сделать класс динамического массива шаблонным. Вот, вроде бы сделал, но наткнулся на ошибку, что не так? Код: ...

Реализовать классы "Воин", "Пехотинец", "Винтовка", "Матрос", "Кортик" (наследование) - C++
Разработать программу с использованием наследования классов, реализующую классы: − воин; − пехотинец(винтовка); − матрос(кортик). ...

Создать класс "Вентилятор" содержащий в себе классы: "Двигатель", "Контроллер", "Пульт управления" - C++
Помогите с кодом написания задачи, не понимаю как написать классы в классе. Нужно создать класс &quot;вентилятор&quot; содержащий в себе классы:...

Создать класс "Книга" с полями "название книги", "количество страниц", "год издания" - C++
Создать класс Книга поля: название книги,количество страниц,год издания методы: вычислить сколько лет книге и количество дней прошедших...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
25.02.2012, 23:26
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru