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

Написал свой string. Проверьте код на наличие подводных камней, утечек памяти и других ошибок

29.01.2016, 11:30. Показов 1690. Ответов 20
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Сделал класс, который ведет себя аналогично char*, но с возможностью сложения строк. Вроде все работает как надо, но есть ли какие-то подводные камни, утечки памяти? Может что-то сделано криво и можно поумнее? Дело в том, что на этот класс мне надо будет потом полностью полагаться и быть уверенным, что в нем нет ошибок. Вот код:

vstring.h
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
class vstring
    {
    private:
        char* Str;
        int length;
    public:
        vstring(char* str = 0);
        vstring(char s);
        vstring(vstring& str);
 
        ~vstring(){delete [] Str;}
 
        char operator[](int index);
 
        friend std::ostream& operator<<(std::ostream& out, vstring& str);
 
        vstring operator+(vstring& str);
        vstring operator+(char symbol);
        friend vstring operator+(char symbol, vstring& str);
 
        operator char*();
 
        vstring& operator=(char* s);
        vstring& operator=(vstring& str);
         };
vstring.cpp
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
vstring::vstring(char* str)
{
    if(str == 0)
    {
        Str = new char[1];
        length = 0;
        Str[0] = '\0';
        return;
    }
    for(length = 0; str[length] != '\0'; length++);
    Str = new char[length+1];
    Str[length] = '\0';
    for(int i(0); i < length; i++)
        Str[i] = str[i];
}
vstring::vstring(char s)
{
    Str = new char[2];
    length = 1;
    Str[1] = '\0';
    Str[0] = s;
}
 
vchar vstring::operator[](int index)
{
    return Str[index];
}
 
vstring::vstring(vstring& str)
{
    Str = new char [str.length+1];
 
    for(int i(0); i < str.length; i++)
        Str[i] = str[i];
    Str[str.length] = '\0';
    length = str.length;
}
 
std::ostream& operator<<(std::ostream& out, vstring& str)
{
    for(int i(0); i < str.length; i++)
        out << str[i];
    return out;
}
 
vstring operator+(char symbol, vstring& str)
{
    return vstring(symbol) + str;
}
 
vstring vstring::operator+(vstring& str)
{
    char* resStr = new char[length + str.length + 1];
 
    int i(0);
    for(; i < length; i++)
        resStr[i] = Str[i];
    for(; i < length + str.length; i++)
        resStr[i] = str[i-length]; 
    resStr[i] = '\0';
        
        vstring ret(resStr);
        delete [] resStr;
    return ret;
}
 
vstring vstring::operator+(char symbol)
{
    return *this + vstring(symbol);
}
 
vstring& vstring::operator=(char* s)
{
    delete [] Str;
 
    vstring str(s);
 
    Str = new char[str.length+1];
    for(int i(0); i < str.length; i++)
        Str[i] = str[i];
    Str[str.length] = '\0';
    length = str.length;
 
    return *this;
}
 
vstring& vstring::operator=(vstring& str)
{
    delete [] Str;
 
    Str = new char[str.length+1];
    for(int i(0); i < str.length; i++)
        Str[i] = str[i];
    Str[str.length] = '\0';
    length = str.length;
 
    return *this;
}
 
vstring::operator char*()
{
    char* str = new char[length+1];
    for(int i(0); i < length; i++)
        str[i] = Str[i];
    str[length] = '\0';
 
    return str;
}
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
29.01.2016, 11:30
Ответы с готовыми решениями:

Проверьте код на наличие ошибок.
проверте пож, в чем ошибки???? #include &lt;stdlib.h&gt; #include &lt;string.h&gt; #include &lt;stdio.h&gt; ...

Проверьте пожалуйста код на наличие ошибок
Проверить код на наличие ошибок. #include &lt;iostream&gt; #include &quot;stdafx.h&quot; using namespace...

Проверьте код программы на наличие ошибок
program zadacha9; const nmax=100; type mas=array of real; var n,i,k,kol:integer; z:real;...

Неверное вычисление выражения: проверьте код на наличие ошибок
program z1; var y,x,z: integer; begin writeln ('x '); readln (x); writeln ('x '); readln (y);...

20
Dimension
594 / 462 / 223
Регистрация: 08.04.2014
Сообщений: 1,710
29.01.2016, 11:36 2
это все уже есть в string , зачем свои велосипед делать не понимаю
0
1 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 31
29.01.2016, 11:43  [ТС] 3
Dimension, это для школы, мы там только велосипеды и изобретаем.
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,736
Записей в блоге: 1
29.01.2016, 11:47 4
Лучший ответ Сообщение было отмечено gru74ik как решение

Решение

C++
1
2
3
4
vstring(vstring& str);
vstring& operator=(vstring& str);
vstring(char* str = 0);
vstring& operator=(char* s);
Почему параметры не const?
Разве нельзя копировать константную строку?
C++
1
friend std::ostream& operator<<(std::ostream& out, vstring& str);
а константные строки выводу не подлежат?
C++
1
int length;
почему знаковый тип?
Думаете, длина строки когда-то будет меньше нуля?
C++
1
char operator[](int index);
опять же, почему параметр имеет знаковый тип?
Почему возвращается не ссылка на символ, а копия?
C++
1
2
        vstring operator+(vstring& str);
        vstring operator+(char symbol);
Почему функции-члены не const?
Ну и ссылка в параметре тоже не const почему?
C++
1
operator char*();
хреновая идея. Возможны неявные касты,
а значит могут быть ошибки потом, которые черт поймаешь.
Лучше сделайте функцию-член c_str
C++
1
vchar vstring::operator[](int index)
что за vchar?
если это псевдоним,
то почему в объявлении char, а не vchar?
C++
1
for(length = 0; str[length] != '\0'; length++);
strlen и strcpy уже не в ходу?
C++
1
2
3
4
5
6
7
8
9
vstring::operator char*()
{
    char* str = new char[length+1];
    for(int i(0); i < length; i++)
        str[i] = Str[i];
    str[length] = '\0';
 
    return str;
}
Возвращаем копию строки, созданную динамически,
при этом заботу об освобождении возлагаем на клиента?
Фигня сразу. И спровоцирует чертову тучу утечек, т.к. неявный каст, см. выше.
C++
1
2
3
4
5
    Str = new char[str.length+1];
    for(int i(0); i < str.length; i++)
        Str[i] = str[i];
    Str[str.length] = '\0';
    length = str.length;
strcpy всё еще не в ходу.
Ну тогда хоть в свою функцию всё это дело оберните,
а то наплодили один и тот же код в тысячи местах. Не хорошо это

Вроде пока всё. Как исправите, приходите
4
Эксперт С++
2924 / 1274 / 114
Регистрация: 27.05.2008
Сообщений: 3,465
29.01.2016, 11:49 5
Ну, написание своих велосипедов - лучший способ обучения.

Касательно самого кода: он у меня даже не компиляется (GCC 4.9), поэтому в дальнейшем анализе на "какие-то подводные камни, утечки памяти" не вижу смысла.
0
1 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 31
29.01.2016, 12:00  [ТС] 6
Croessmah, спасибо, буду исправлять, видите, все же надо иногда учиться на велосипедах.CheshireCat, думаю, это из-за того vchar вместо char (описка) в строке 24 vstring.cpp
0
Эксперт С++
2924 / 1274 / 114
Регистрация: 27.05.2008
Сообщений: 3,465
29.01.2016, 12:06 7
Да, одна из ошибок была именно про vchar. Исправляй, как только код скомпиляется, погляжу более подробно и попробую написать несколько тестов, "ломающих" твой код.
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,736
Записей в блоге: 1
29.01.2016, 12:10 8
Цитата Сообщение от vaziliybober Посмотреть сообщение
Croessmah, спасибо, буду исправлять, видите, все же надо иногда учиться на велосипедах.
Я этого не отрицал. Сам писал.
0
1 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 31
29.01.2016, 21:30  [ТС] 9
Цитата Сообщение от CheshireCat Посмотреть сообщение
Исправляй, как только код скомпиляется, погляжу более подробно и попробую написать несколько тестов, "ломающих" твой код.
Если подключить <iostream> в vstring.h и "vstring.h" в vstring.cpp, то у меня на моем vs_2012 все компилится. Ну еще #pragma once можно на всякий. Мой косяк, не знаю, зачем я все это опустил.
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,736
Записей в блоге: 1
29.01.2016, 22:35 10
Цитата Сообщение от vaziliybober Посмотреть сообщение
Ну еще #pragma once можно на всякий
тогда можем попасть впросак,
если нет include guard'ов, т.к. прагмы не стандартны.
Также нет main'а, чтобы посмотреть как Вы всё это используете
0
1 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 31
29.01.2016, 23:06  [ТС] 11
Цитата Сообщение от Croessmah Посмотреть сообщение
Как исправите, приходите
ну вот вроде все.

vstring.h
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
#pragma once
#include <iostream>
 
class vstring
    {
    private:
        char* Str;
        unsigned int length;
 
        char* string_copy(const char* str);
        unsigned int string_length(const char* str);
    public:
        vstring(const char* str = 0);
        vstring(char s);
        vstring(const vstring& str);
 
        ~vstring(){delete [] Str;}
 
        char& operator[](unsigned int index) const;
 
        friend std::ostream& operator<<(std::ostream& out, const vstring& str);
 
        vstring operator+(const vstring& str) const;
        vstring operator+(char symbol) const;
        friend vstring operator+(char symbol, vstring& str);
 
        vstring& operator=(const char* s);
        vstring& operator=(const vstring& str);
 
        char* c_str();
    };
vstring.cpp
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
#include "vstring.h"
 
unsigned int vstring::string_length(const char* str)
{
    if(str == 0) return 0;
 
    unsigned int size;
    for(size = 0; str[size] != '\0'; size++);
    return size;
}
 
char* vstring::string_copy(const char* str)
{
    if(str == 0)
    {
        char* ret = new char[1];
        ret[0] = '\0';
        return ret;
    }
 
    char* ret = new char[string_length(str)+1];
    ret[string_length(str)] = '\0';
    for(int i(0); i < string_length(str); i++)
        ret[i] = str[i];
    return ret;
}
 
vstring::vstring(const char* str)
{
    Str = string_copy(str);
    length = string_length(str);
}
vstring::vstring(char s)
{
    Str = new char[2];
    length = 1;
    Str[1] = '\0';
    Str[0] = s;
}
 
char& vstring::operator[](unsigned int index) const
{
    return Str[index];
}
 
vstring::vstring(const vstring& str)
{
    Str = string_copy(str.Str);
    length = str.length;
}
 
std::ostream& operator<<(std::ostream& out, const vstring& str) 
{
    for(int i(0); i < str.length; i++)
        out << str[i];
    return out;
}
 
vstring operator+(char symbol, vstring& str)
{
    return vstring(symbol) + str;
}
 
vstring vstring::operator+(const vstring& str) const
{
    char* resStr = new char[length + str.length + 1];
 
    int i(0);
    for(; i < length; i++)
        resStr[i] = Str[i];
    for(; i < length + str.length; i++)
        resStr[i] = str[i-length]; 
    resStr[i] = '\0';
        
        vstring ret(resStr);
        delete [] resStr;
    return ret;
}
 
vstring vstring::operator+(char symbol) const
{
    return *this + vstring(symbol);
}
 
vstring& vstring::operator=(const char* s)
{
    delete [] Str;
    Str = string_copy(s);
    length = string_length(s);
 
    return *this;
}
 
vstring& vstring::operator=(const vstring& str)
{
    delete [] Str;
 
    Str = string_copy(str.Str);
    length = str.length;
 
    return *this;
}
 
char* vstring::c_str()
{
    return string_copy(Str);
}
Цитата Сообщение от Croessmah Посмотреть сообщение
Также нет main'а, чтобы посмотреть как Вы всё это используете
Да пока никак не использую. Как раз и обратился, чтобы потом использовать без сомнений в работе класса.

Добавлено через 4 минуты
Цитата Сообщение от Croessmah Посмотреть сообщение
тогда можем попасть впросак,
если нет include guard'ов, т.к. прагмы не стандартны.
ну пусть подключит стандартные include guardы вместо прагмы.
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,736
Записей в блоге: 1
29.01.2016, 23:12 12
Цитата Сообщение от vaziliybober Посмотреть сообщение
ну пусть подключит стандартные include guardы вместо прагмы.
Это Ваша задача - Вы же разработчик этого инструмента
C++
1
2
3
4
char* vstring::c_str()
{
    return string_copy(Str);
}
Зачем что-то копировать и выделять?
C++
1
2
3
4
const char* vstring::c_str() const //объявление подправить соответственно. Добавить noexcept по возможности.
{
    return Str ;
}
0
1 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 31
29.01.2016, 23:25  [ТС] 13
Цитата Сообщение от Croessmah Посмотреть сообщение
Зачем что-то копировать и выделять?
вот зачем
C++
1
2
3
4
vstring* str1 = new vstring("hello");
    char* str2 = str1->c_str();
    delete str1;
    cout << str2; // выдает крабозябры, т. к. удалился адрес Str (это если не копировать)
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
29.01.2016, 23:34 14
Цитата Сообщение от vaziliybober Посмотреть сообщение
char& vstring::operator[](unsigned int index) const
{
* * return Str[index];
}
у вас метод константный.
это значит, что он работает в режиме "только для чтения".
но при этом он возвращает мутабельный символ.

вы уверены, что это правильно:
изменять данные, которые возвращают константные методы?

ведь технически, получается, что таким образом
можно изменить символ константной от рождения строки,
и нарваться на UB

Добавлено через 4 минуты
Цитата Сообщение от vaziliybober Посмотреть сообщение
вот зачем

vstring* str1 = new vstring("hello");
* * char* str2 = str1->c_str();
* * delete str1;
* * cout << str2; // выдает крабозябры, т. к. удалился адрес Str (это если не копировать)
привет, говнокод и утечки памяти.
0
1 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 31
29.01.2016, 23:36  [ТС] 15
hoggy, я даже не знаю, что такое мутабельный символ. Никаких глубоких рассуждений у меня не было. Я просто не мог вызвать метод вот тут:
C++
1
2
3
4
5
6
std::ostream& operator<<(std::ostream& out, const vstring& str) 
{
    for(int i(0); i < str.length; i++)
        out << str[i]; // здесь
    return out;
}
Поэтому и приписал const.
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,736
Записей в блоге: 1
29.01.2016, 23:36 16
Цитата Сообщение от vaziliybober Посмотреть сообщение
вот зачем
а нефиг криво использовать.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
29.01.2016, 23:39 17
Цитата Сообщение от vaziliybober Посмотреть сообщение
Поэтому и приписал const.
замените:
C++
1
2
char& vstring::operator[](unsigned int index) const
    { return Str[index]; }
на:

C++
1
2
3
4
5
const char& vstring::operator[](unsigned int index) const
    { return Str[index]; }
 
char& vstring::operator[](unsigned int index) 
    { return Str[index]; }
либо на:

C++
1
2
char vstring::operator[](unsigned int index) const
    { return Str[index]; }
0
1 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 31
29.01.2016, 23:47  [ТС] 18
hoggy, спасибо, исправил.

Цитата Сообщение от Croessmah Посмотреть сообщение
а нефиг криво использовать.
Но все же объясните 14-летнему чайнику-говнокодеру, как "ровно" использовать c_str(). Я ж просто хотел возможность преобразовывать в char*. Зачем мне в const char*?
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
29.01.2016, 23:52 19
Цитата Сообщение от vaziliybober Посмотреть сообщение
как "ровно" использовать c_str().
вот жеж:

Цитата Сообщение от Croessmah Посмотреть сообщение
const char* vstring::c_str() const //объявление подправить соответственно. Добавить noexcept по возможности.
{
* * return Str ;
}
если объект-строка уничтожен,
значит данные строки тоже уничтожены.
значит любые указатели выданные наружу более не действительные.

об этом нужно знать и помнить,
когда вы снаружи кэшируете данные во внешних указателях.
0
1 / 1 / 0
Регистрация: 02.01.2016
Сообщений: 31
30.01.2016, 00:03  [ТС] 20
Цитата Сообщение от hoggy Посмотреть сообщение
об этом нужно знать и помнить,
когда вы снаружи кэшируете данные во внешних указателях.
ну а в конструкторах копирования мы ж без сомнений дублируем данные. Почему тогда в них нет таких заморочек?
0
30.01.2016, 00:03
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.01.2016, 00:03
Помогаю со студенческими работами здесь

Как проверить наличие утечек памяти в шаблоне?
при удалении дерева есть подозрение что часть не удаляется. Количество вызовов деструкторов узлов...

Проверьте, на наличие ошибок
Накалякал код, по методичке, компилятора на компе нет. Проверьте, пожалуйста, скомпилируется ли код...

Проверьте на наличие ошибок
В var должно быть 10 значений, а в readln 8. Помогите дополнить 3 и 7 строчку. PROGRAM z3; CONST...

Проверьте, пожалуйста, на наличие ошибок
Есть код:#include &lt;iostream&gt; #include &lt;string&gt; using namespace std; struct Hotel{ string F, I,...


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

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