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

Инициализация укзателей в классе - C++

Восстановить пароль Регистрация
 
moskitos80
 Аватар для moskitos80
39 / 39 / 0
Регистрация: 04.10.2011
Сообщений: 128
30.09.2012, 17:51     Инициализация укзателей в классе #1
Всем привет читаю книгу Пабло Халперна "Стандарная библиотека С++ на примерах". Там, в качестве обучения читателю предлагается пройти процесс разработки и реализации некоего приложения - записной книжки с использованием STL. Вопрос касается инициализации указателей на массивы строк, и удаление их.
В общем, есть некий класс, автор его реализовал примерно так (это предварительная версия - дальше автор реализует этот класс с использованием типа std::string - кабы люди, не читавшие данной книги не подумали чего нехорошего про автора ):
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
class Address
{
    public:
        Address::Address()
        : lastname_     (new char[1])
        , firstname_    (new char[1])
        , phone_        (new char[1])
        , address_      (new char[1])
        {
            this->lastname_[0]  = '\0'; 
            this->firstname_[0] = '\0'; 
            this->phone_[0]     = '\0';
            this->address_[0]   = '\0';
        }
        ~Address()
        {
            delete [] this->firstname_;
            delete [] this->lastname_;
            delete [] this->phone_;
            delete [] this->address_;
        }
        
        //  . . . Много другого кода . . .
        
    private:
        char *lastname_;
        char *firstname_;
        char *phone_;
        char *address_;
};
А я (только изучаю С++), не подглядывая в реализацию в книжке, но представляя, что нужно сделать, реализовал его вот так:
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
class Address
{
    public:
        Address()
        : lastname_ (NULL)
        , firstname_(NULL)
        , phone_    (NULL)
        , address   (NULL)
        {
            /* пусто */
        }
        ~Address()
        {
            delete this->firstname_;
            delete this->lastname_;
            delete this->phone_;
            delete this->address_;
        }
        
        //  . . . Много другого кода . . .
        
    private:
        char *lastname_;
        char *firstname_;
        char *phone_;
        char *address_;
};
Вопрос в том, правильно ли я работаю с указателями? - Подозреваю, что нет. И какие ошибки я допускаю в данном случае?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
MrCold
851 / 749 / 71
Регистрация: 11.01.2012
Сообщений: 1,942
30.09.2012, 18:13     Инициализация укзателей в классе #2
А нет вообще то ошибки не будет все корректно
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
30.09.2012, 18:25     Инициализация укзателей в классе #3
не совсем так.
по стандарту, оператор delete ничего не делает с нулевыми указателями. поэтому, если указатель инициализировать нулем (а ТС это сделал), то все корректно отработает.
C++
1
2
char* p = 0;
delete p; // ok
писать this пожалуй лишнее. редко встречал код-стайлы, где требовали это делать.
ну и еще если первый листинг из книжки - то сам автор демонстрирует написание кода, небезопасного с точки зрения исключений. в нем возможны утечки.
в списке инициализации больше одного new для инициализации голых указателей писать не стоит.
MrCold
851 / 749 / 71
Регистрация: 11.01.2012
Сообщений: 1,942
30.09.2012, 18:26     Инициализация укзателей в классе #4
Если указатели обнулили то при вызове оператора delete
ошибки не будет
moskitos80
 Аватар для moskitos80
39 / 39 / 0
Регистрация: 04.10.2011
Сообщений: 128
30.09.2012, 18:42  [ТС]     Инициализация укзателей в классе #5
Цитата Сообщение от MrCold Посмотреть сообщение
Если указатели обнулили то при вызове оператора delete
ошибки не будет
А... как бы во время работы указатели конечно же будут указывать на какие то данные, приведу полный листинг класса (как у автора, у меня получилось всё тоже самое, но разница была в том, что показывают листинги в начале топика). Класс просто является контейнером, который имеет 4 текстовых поля и методы для установки и получения значений + перегруженные оператор и конструктор копирования, .
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
class Address
{
    public: 
        Address()
        : lastname_     (new char[1])
        , firstname_    (new char[1])
        , phone_        (new char[1])
        , address_      (new char[1])
        {
            this->lastname_[0]  = '\0';
            this->firstname_[0] = '\0';
            this->phone_[0]     = '\0'; 
            this->address_[0]   = '\0';
        }       
        ~Address()
        {
            delete [] this->firstname_;
            delete [] this->lastname_;
            delete [] this->phone_;
            delete [] this->address_;
        }       
        Address(const Address &a)
        : lastname_     (0)
        , firstname_    (0)
        , phone_        (0)
        , address_      (0)
        {
            *this = a;
        }       
        const Address& operator = (const Address &a)
        {
            if (this != &a) {
                this->lastname(a.lastname());
                this->firstname(a.firstname());
                this->phone(a.phone());
                this->address(a.address());
            }
            return *this;
        }
        
        // Чтение lastname
        const char* lastname() const {return this->lastname_;}
        // Запись lastname
        void lastname(const char* s)
        {
            if (this->lastname_ == s) return;
            delete [] this->lastname_;
            this->lastname_ = this->dup(s);
        }
        
        // Чтение firstname
        const char* firstname() const {return this->firstname_;}
        // Запись firstname
        void firstname(const char* s)
        {
            if (this->firstname_ == s) return;
            delete [] this->firstname_;
            this->firstname_ = this->dup(s);
        }
        
        // Чтение phone
        const char* phone() const {return this->phone_;}
        // Запись phone
        void phone(const char* s)
        {
            if (this->phone_ == s) return;
            delete [] this->phone_;
            this->phone_ = this->dup(s);
        }
        
        // Чтение address
        const char* address() const {return this->address_;}
        // Запись address
        void address(const char* s)
        {
            if (this->address_ == s) return;
            delete [] this->address_;
            this->address_ = this->dup(s);
        }
        
    private:
        char *lastname_;
        char *firstname_;
        char *phone_;
        char *address_;
        
        // Глубинное копирование данных указателя:
        char* dup(const char *s)
        {
            char *newstr = new char [std::strlen(s) + 1];
            std::strcpy(newstr, s);
            return newstr;
        }
};
Вот как у меня:
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
class Address
{
    public: 
        Address()
        : lastname_     (NULL)
        , firstname_    (NULL)
        , phone_        (NULL)
        , address_      (NULL)
        { }       
        ~Address()
        {
            delete this->firstname_;
            delete this->lastname_;
            delete this->phone_;
            delete this->address_;
        }       
        Address(const Address &a)
        : lastname_     (NULL)
        , firstname_    (NULL)
        , phone_        (NULL)
        , address_      (NULL)
        {
            *this = a;
        }       
        const Address& operator = (const Address &a)
        {
            if (this != &a) {
                this->lastname(a.lastname());
                this->firstname(a.firstname());
                this->phone(a.phone());
                this->address(a.address());
            }
            return *this;
        }
        
        // Чтение lastname
        const char* lastname() const {return this->lastname_;}
        // Запись lastname
        void lastname(const char* s)
        {
            if (this->lastname_ == s) return;
            delete this->lastname_;
            this->lastname_ = this->dup(s);
        }
        
        // Чтение firstname
        const char* firstname() const {return this->firstname_;}
        // Запись firstname
        void firstname(const char* s)
        {
            if (this->firstname_ == s) return;
            delete this->firstname_;
            this->firstname_ = this->dup(s);
        }
        
        // Чтение phone
        const char* phone() const {return this->phone_;}
        // Запись phone
        void phone(const char* s)
        {
            if (this->phone_ == s) return;
            delete this->phone_;
            this->phone_ = this->dup(s);
        }
        
        // Чтение address
        const char* address() const {return this->address_;}
        // Запись address
        void address(const char* s)
        {
            if (this->address_ == s) return;
            delete this->address_;
            this->address_ = this->dup(s);
        }
        
    private:
        char *lastname_;
        char *firstname_;
        char *phone_;
        char *address_;
        
        // Глубинное копирование данных указателя:
        char* dup(const char *s)
        {
            char *newstr = new char [std::strlen(s) + 1];
            std::strcpy(newstr, s);
            return newstr;
        }
};
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
30.09.2012, 18:51     Инициализация укзателей в классе #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
 if (this->address_ == s)
  return;
 delete this->address_;
 this->address_ = this->dup(s);
 
 
можно было бы заменить на одну функцию:
void clone(const char* src, char*& target)
{
 if (src == target)
  return;
 delete target;
 target = dup(s);
}
 
 
и тогда все функции установки новой строки превращаются в однострочные:
void phone(const char* s)
{
  clone(s, phone_);
}
        
void address(const char* s)
{
  clone(s, target_);
}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
30.09.2012, 19:05     Инициализация укзателей в классе
Еще ссылки по теме:

C++ Инициализация переменной в классе
C++ Инициализация указателя в классе
Инициализация valarray в классе C++

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

Или воспользуйтесь поиском по форуму:
moskitos80
 Аватар для moskitos80
39 / 39 / 0
Регистрация: 04.10.2011
Сообщений: 128
30.09.2012, 19:05  [ТС]     Инициализация укзателей в классе #7
Цитата Сообщение от DU Посмотреть сообщение
неплохо бы еще от копипаста избавится. в коде куча функций с одинаковым кодом
- Да - да. Автор книги обращает внимание на этот момент Всем спасибо.
Yandex
Объявления
30.09.2012, 19:05     Инициализация укзателей в классе
Ответ Создать тему
Опции темы

Текущее время: 22:52. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru