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

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

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 17, средняя оценка - 4.94
CatsCanFly
0 / 0 / 0
Регистрация: 14.04.2013
Сообщений: 21
#1

Повторный вызов конструктора?! - C++

28.07.2013, 20:46. Просмотров 2270. Ответов 39
Метки нет (Все метки)

Мой небольшой класс
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
class CString
{
private:
    char* str;
    int len;
    int real_size;
public:
    CString() : len(0), real_size(10)
    {
        this->str = (char*)malloc(this->real_size * sizeof(char));
    }
 
    CString(char str_arg[])
    {
        this->len = char_arr_length(str_arg);
        this->real_size = this->len + 10;
        this->str = (char*)malloc(this->len * sizeof(char));
        this->set(str_arg);
    }
 
    CString* set(char str_arg[])
    {
        for(int i = 0; str_arg[i] != 0; i++)
        {
            this->str[i] = str_arg[i];
        }
        str[this->len] = 0;
        return this;
    }
 
private:
    int char_arr_length(char str_arg[])
    {
        int i;
        for(i = 0; str_arg[i] != 0; i++);
        return i;
    }
 
    friend ostream & operator << (ostream & output, CString & _str)
    {
        output << _str.str;
        return output;
    }
};
Как понимаю, одноаргументные конструкторы можно вызывать как будто это присваивание:
C++
1
2
CString str = "test";
cout<<str;
Естественно , все работает, но мое удивление вызвало :
C++
1
2
3
CString str = "test";
str = "test2";
cout<<str;
- Тоже работает. Оператор присваивания для класса не перегружен. Притом что если явным образом еще раз вызвать конструктор от этого объекта, компилятор конечно ругается. Объясните пожалуйста, что здесь вообще тогда происходит? Еще раз вызывается конструктор и создается новый объект, а старый продолжает висеть в памяти и ссылка на него теряется?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
28.07.2013, 20:46
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Повторный вызов конструктора?! (C++):

Повторный вызов конструктора класса - C++
class X { public: X() {a = 10;}; setA(int value) {a = value;}; private: int a; };

Повторный вызов деструктора - C++
{ bar b; b.~bar(); } В данном примере деструктор bar вызовется дважды. Как у уже удаленного объекта может вызываться...

Повторный вызов процедуры - C++
Всем очень добрый день! А подскажите,пожалуйста,в Си++ процедура может вызываться несколько раз в различных местах кода,как в Паскале?

Повторный вызов деструктора для объекта - C++
Здравствуйте! К сожалению, я пока не умею пользоваться отладчиком для анализа работы программ, поэтому в очередной раз обращаюсь к вам...

Исключительные ситуации (повторный вызов деструктора) - C++
Всем привет ! Подскажите пожалуйста , почему повторно вызываются деструкторы класса A,B,C? #include &lt;stdio.h&gt; #include...

вызов конструктора - C++
Здарова! Есть допустим класс: class Str { Str(); Str(Str&amp;); Str(char*); };

39
VLK
29.07.2013, 22:11     Повторный вызов конструктора?!
  #16

Не по теме:

CatsCanFly, а от куда взята эта программа

0
alsav22
5421 / 4816 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
29.07.2013, 22:16 #17
Вот это, по-моему, лишнее:
C++
1
 int char_arr_length(char str_arg[])
strlen() делает тоже самое.
0
CatsCanFly
0 / 0 / 0
Регистрация: 14.04.2013
Сообщений: 21
29.07.2013, 22:17  [ТС] #18
Цитата Сообщение от VLK Посмотреть сообщение

Не по теме:

CatsCanFly, а от куда взята эта программа

Сам написал конечно, поэтому и спрашиваю по ней. Нужно реализовать класс наподобие std:string, не используя ни его, ни желательно функции из cstring. Так же вопрос по этому классу еще
C++
1
2
3
    CString str = "test";
    CString str2 = "test2";
    str = str2;
Программа запускается и выполняется, но после завершения выдается:
Windows has triggered a breakpoint in lafore.exe.

This may be due to a corruption of the heap, which indicates a bug in lafore.exe or any of the DLLs it has loaded.
Что я не так сделал?
0
stragger
39 / 39 / 2
Регистрация: 05.12.2011
Сообщений: 343
29.07.2013, 22:18 #19
CatsCanFly, ну, если по коду посмотреть, то мне не нравится, что ты используешь для выделения памяти malloc/free, а не оператор new/delete. Если пишешь на C++ рекомендуется использовать new/delete, да и удобней он, имхо
0
CatsCanFly
0 / 0 / 0
Регистрация: 14.04.2013
Сообщений: 21
29.07.2013, 22:23  [ТС] #20
Цитата Сообщение от stragger Посмотреть сообщение
CatsCanFly, ну, если по коду посмотреть, то мне не нравится, что ты используешь для выделения памяти malloc/free, а не оператор new/delete. Если пишешь на C++ рекомендуется использовать new/delete, да и удобней он, имхо
Использую для того что бы сделать например конкатенацию строк, если сумма длин при конкатенации получится больше выделенной памяти, использовать realloc. А как это сделать с new?
0
VLK
194 / 163 / 12
Регистрация: 05.05.2013
Сообщений: 1,225
29.07.2013, 22:28 #21
В учебнике у меня была подобная программа, я ее переписывал \ совершенствовал, вот, может будет интересно:

Кликните здесь для просмотра всего текста
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <iostream> 
 
class str
{
public:
 
~str() // Деструктор, удаляет массив
{
delete[] stroka;
dlina_stroki = 0;
}
 
str() // Конструктор по умолчанию, создает массив нулевой длины
{
stroka = new char[1];
stroka[0] = '\0';
dlina_stroki = 0;
}
 
str(const char *rhs) // конструктор, преобразует массив символов в строчку
{
dlina_stroki = strlen(rhs); // устанавливаем длину массива при помощи оператора strlen
stroka = new char[dlina_stroki +1]; // выделяем память под массив на 1 элемент больше
 
for (int i = 0; i < dlina_stroki; i++)
{ stroka[i] = rhs[i]; } // переводим полученные данные (rhs) в свой массив (stroka)
stroka[dlina_stroki] = '\0'; // вставляем в последний элемент массива пробел 
}
 
str(const str & rhs) // конструктор копировщик, работает по тому же принципу что и конструктор выше, принимает значение в качестве ссылки,если НЕ в качестве ссылки, то будет бесконечная рекурсия!
{
dlina_stroki = rhs.get_dlina_stroki();
stroka = new char[dlina_stroki + 1];
 
for (int i = 0; i < dlina_stroki; i++)
{ stroka[i] = rhs[i]; }
stroka[dlina_stroki] = '\0';
}
 
char operator[] (int rhs) const // данный оператор получает номер элемента массива, а так же проверяет, не выходит ли массив за область видимости
{
if (dlina_stroki < rhs)
{ return stroka[dlina_stroki - 1]; }
else
{ return stroka[rhs]; }
}
 
char & operator[] (int rhs) // данный оператор получает номер элемента массива, а так же проверяет, не выходит ли массив за область видимости
{  
if (dlina_stroki < rhs)
{ return stroka[dlina_stroki - 1]; }
else
{ return stroka[rhs]; }
}
 
str & operator= (const str & rhs) // оператор равно для класса str 
{
if (this == &rhs) // проверяем, не пытаемся ли мы приравнять один и тот же объект т.е. var = var
{ return *this; } // если пытаемся, то просто возвращаем ссылку на него
 
delete[] stroka; // удаляем, то, что есть сейчас
dlina_stroki = rhs.get_dlina_stroki(); // узнаем новую длину строки
stroka = new char[dlina_stroki + 1]; // выделяем память под новый массив
 
for (int i = 0; i < dlina_stroki; i++)
{ stroka[i] = rhs[i];  } // переводим полученные данные (rhs) в свой массив (stroka)
stroka[dlina_stroki] = '\0'; // вставляем в последний элемент массива пробел
return *this; // возвращаем новое значение
}
 
str operator+ (const str & rhs)
{
int temp_dlina_stroki = get_dlina_stroki() + rhs.get_dlina_stroki(); // Узнаем необходимую длину строки для двух объектов
str temp(temp_dlina_stroki + 2); // выделяем память под новый временный объект
int i = 0;
int j = 0;
 
for (i; i < dlina_stroki; i++)
{ temp[i] = stroka[i]; } // переводим первую часть во временный массив
 
temp[i] = ' '; // вставляем между массивами (строчками) пробел
i++;
 
for (j ; j < rhs.get_dlina_stroki(); j++, i++ ) 
{ temp[i] = rhs[j];  } // переводим вторую часть во временный массив
 
temp[temp_dlina_stroki + 1] = '\0'; // вставляем в последний элемент массива пробел
return temp; // возвращаем в качестве результата временны объект
}
 
void operator+= (const str & rhs)
{
int rhs_dlina_stroki = rhs.get_dlina_stroki();
int obsh_dlina_stroki = rhs_dlina_stroki + dlina_stroki;
 
str temp(obsh_dlina_stroki + 1);
 
int i, w;
 
for (i = 0; i < dlina_stroki; i++)
{ temp[i] = stroka[i]; }
 
for (w = 0; w < rhs_dlina_stroki; w++, i++)
{ temp[i] = rhs[i-dlina_stroki]; }
temp[obsh_dlina_stroki] = '\0';
*this = temp;
// данный оператор выполняет следующие - varOne += varTwo - varOne = varOne + varTwo
}
 
char *get_stroka() const { return stroka; } // функция член, возвращает массив
int get_dlina_stroki() const { return dlina_stroki; } // функция член, возвращает длину массива
void show_stroka() const { std::cout << stroka << "\n"; } // функция член, выводит на экран строку
 
private:
str(int rhs)
{
dlina_stroki = rhs;
stroka = new char[dlina_stroki +1];
for (int i = 0; i < dlina_stroki; i++)
{ stroka[i] = '\0'; }
stroka[dlina_stroki] = '\0';
}
 
char *stroka; // массив в котором хранится строка
int dlina_stroki; // длина массива
};
0
stragger
39 / 39 / 2
Регистрация: 05.12.2011
Сообщений: 343
29.07.2013, 22:38 #22
Цитата Сообщение от CatsCanFly Посмотреть сообщение
Использую для того что бы сделать например конкатенацию строк, если сумма длин при конкатенации получится больше выделенной памяти, использовать realloc. А как это сделать с new?
Создать буффер нужного размера с помощью new, скопировать туда содержимое строк и дальше этот буффер присвоить результируещей строке(предварительно удалив с помощью delete, чтобы утечки не было)

По сути, realloc делает тоже самое.

Добавлено через 4 минуты
CatsCanFly, насчет ошибки.
C
1
str = str2
здесь после этой строки str - это побайтовая копия str2. Указатель char* str; один и тот же.
Когда срабатывает деструктор для str и str2 по этому указателю удаление происходит два раза, на втором разе будет ошибка.

Решение: определить оператор = для строк.
0
OhMyGodSoLong
~ Эврика! ~
1244 / 993 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
29.07.2013, 22:43 #23
Цитата Сообщение от stragger Посмотреть сообщение
По сути, realloc делает тоже самое.

Не по теме:

Если ему не повезёт и он не сможет довыделить память из излишков или от границы кучи.

1
CatsCanFly
0 / 0 / 0
Регистрация: 14.04.2013
Сообщений: 21
30.07.2013, 00:54  [ТС] #24
И снова небольшой вопрос Извиняюсь за назойливость:
вот мой класс на данный момент:
Кликните здесь для просмотра всего текста
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
class CString
{
private:
    char* str;
    int len;
    int real_size;
public:
    CString() : len(0), real_size(0)
    {
 
    }
 
    CString(char str_arg[])
    {
        this->len = strlen(str_arg);
        this->real_size = this->len + 10;
        this->str = new char[this->real_size];
        this->set(str_arg);
    }
 
    CString (const CString & x)
    {
        this->len = x.len;
        this->real_size = x.real_size;
        this->str = new char[this->real_size];
        this->set(x.str);
    }
 
    CString & operator=(char str_arg[])
    {
        this->len = this->strlen(str_arg);
        if (this->len >= this->real_size)
        {
            this->reallocate(this->len + 10);
        }
        this->set(str_arg);
        return *this;
    }
 
    CString & operator =(const CString & x)
    {
        this->len = x.len;
        if (this->len >= this->real_size)
            this->reallocate(this->len + 10);
        this->set(x.str);
        return *this;
    }
 
    CString operator + (const CString & x)
    {
        int new_len = this->len + x.len;
        int new_r_size = this->real_size + x.len;
        char* temp = concat_chars(x.str, x.len);        
        return CString(new_r_size, new_len, temp);
    }
 
    CString operator + (char str_arg[])
    {
        int arg_len = this->strlen(str_arg);
        int new_len = this->len + arg_len;
        int new_r_size = this->real_size + arg_len;
        char* temp = concat_chars(str_arg, arg_len);        
        return CString(new_r_size, new_len, temp);
    }
 
    bool operator == (const CString & _str)
    {
        if (this->len != _str.len)
            return false;
        for (int i = 0; i < this->len; i++)
        {
            if (_str.str[i] != this->str[i])
                return false;
        }
        return true;
    }
 
    bool operator != (const CString & _str)
    {
        if (this->len != _str.len)
            return true;
        for (int i = 0; i < this->len; i++)
        {
            if (_str.str[i] != this->str[i])
                return true;
        }
        return false;
    }
 
    char &operator [] (int addr)
    {
        return this->str[addr];
    }
 
    ~CString()
    {
        delete[] this->str;
    }
 
private:
    CString (int _real_size, int _len, char* _str)
    {
        this->len = _len;
        this->real_size = _real_size;
        this->str = _str;
    }
 
    int strlen(char str_arg[])
    {
        int i;
        for(i = 0; str_arg[i] != 0; i++);
        return i;
    }
 
    void reallocate(int new_length)
    {
        this->real_size = new_length;
        delete[] this->str;
        this->str = new char[this->real_size];
    }
 
    void set(char* str_arg)
    {
        for(int i = 0; str_arg[i] != 0; i++)
        {
            this->str[i] = str_arg[i];
        }
        str[this->len] = 0;
    }
 
    char* concat_chars(char* part2, int len2)
    {
        int new_len = this->len + len2;
        char* temp = new char[this->real_size + len2];
        int pointer;
        for(pointer = 0; pointer < this->len; pointer++)
        {
            temp[pointer] = this->str[pointer];
        }
        for(int i = 0; pointer < new_len; pointer++, i++)
        {
            temp[pointer] = part2[i];
        }
        temp[new_len] = 0;
        return temp;
    }
 
    friend ostream & operator << (ostream & output, CString & _str)
    {
        output << _str.str;
        return output;
    }
};

Если сделать так:
C++
1
2
3
CString str1 = "text";
CString str2 = "other";
CString str3 = str1 + str2;
то создается временный объект внутри кода перегруженного оператора + и возвращается им. Только тут получается, что после присваивания str3 мы временный объект теряем, соответственно указатель на массив char который он в себе содержит, и возможность освободить от него память, то есть получаем утечку памяти. Я прав? Подскажите пожалуйста, как решить такую проблему. VLK в своем решении использовал тот же подход что и я, и как понимаю там проблема эта тоже должна быть.
0
VLK
194 / 163 / 12
Регистрация: 05.05.2013
Сообщений: 1,225
30.07.2013, 11:23 #25
C++
1
2
str test = "Hello world";
str test("Hello world");
у меня в обоих случая вызывался только один конструктор (насколько я понял проблема в том, что вызывалось несколько)
0
Jupiter
Каратель
Эксперт С++
6556 / 3977 / 227
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
30.07.2013, 11:30 #26
у меня в обоих случая вызывался только один конструктор
а теперь открываем g++ и компилим с -fno-elide-constructors.
или g++ своевольничает и нарушает стантадарт?

Добавлено через 49 секунд
цитату из стандарта об эквивалентности этих двух строк от Dmitriy_M так и не получили
0
VLK
194 / 163 / 12
Регистрация: 05.05.2013
Сообщений: 1,225
30.07.2013, 11:40 #27
Я не знаю что за g++, что даст "g++ и компилим с -fno-elide-constructors" ? напишет когда вызывается конструктор?
0
Fyret
185 / 171 / 13
Регистрация: 30.07.2013
Сообщений: 359
30.07.2013, 12:43 #28
Недавно разбирался для себя с темой пропущенного копирования. Jupiter прав, текущий стандарт 12.8/32.

C++
1
CString str = "test";
Тот факт, что msvc и gcc (на них я проверял) по умолчанию опускают вызов конструктора копирования, не означает, что они обязаны так делать.
0
CatsCanFly
0 / 0 / 0
Регистрация: 14.04.2013
Сообщений: 21
30.07.2013, 12:44  [ТС] #29
А по моему последнему вопросу насчет пропадающего объекта и утечки памяти кто то сможет подсказать?
0
Jupiter
Каратель
Эксперт С++
6556 / 3977 / 227
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
30.07.2013, 12:56 #30
Цитата Сообщение от CatsCanFly Посмотреть сообщение
Если сделать так:
C++
1
2
3
CString str1 = "text";
CString str2 = "other";
CString str3 = str1 + str2;
то создается временный объект внутри кода перегруженного оператора + и возвращается им. Только тут получается, что после присваивания str3 мы временный объект теряем, соответственно указатель на массив char который он в себе содержит, и возможность освободить от него память, то есть получаем утечку памяти. Я прав?
для этого временного объекта вызывается декструктор
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
30.07.2013, 12:56
Привет! Вот еще темы с ответами:

Вызов конструктора - C++
void main() { std::string stemporary; int itemporary; float ftemporary; float fftemporary; ECM *pECM; for (int i=0;i&lt;4;i++) ...

вызов конструктора - C++
Почему при повторном вызове конструктора выбивает ошибку ?Вот здесь ObjX(INUSE); no match for call to `(aClass) (int&amp;)' #include...

Вызов конструктора копий - C++
Всех приветствую! Имеется следующий простенький код: #include &lt;iostream&gt; using namespace std; class Object { ...

Вызов конструктора с аргументами - C++
есть класс приложения test_proj в интерфейсе класса в файле test_proj.h создается объект класса Settings. class test_proj { ...


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

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

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