2 / 2 / 0
Регистрация: 24.11.2016
Сообщений: 77
1

Ошибка после перегрузки оператора +

05.08.2017, 17:13. Показов 3151. Ответов 25
Метки нет (Все метки)

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
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
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
class String {
  
 private:
  char* str;
  int size;
 public:
 
     String(): size(0), str(0) {}
 
  String( const char* outStr ) { 
     if ( ! outStr ) {
            size = 0;
            delete [] str;
            str = 0; 
       }
     else {
        size = strlen(outStr);
        str = new char[size+1];
        strcpy( str, outStr );
     }
  }
 
  String( const String& rhs ) { 
        if ( ! rhs.size ) {
        size = 0;
            delete [] str; 
            str = 0;
    }
        else {
            size = rhs.size;
            str = new char[size];
            strcpy( str, rhs.str );
        }
  }
 
  ~String() { delete [] str; }
  
  String& operator=( const String& rhs ) {
           
           if ( ! rhs.size ) {
            size = 0;
            delete [] str; 
            str = 0;
           }
           else {
             size = rhs.size;
             str = new char[size+1];
             strcpy( str, rhs.str );
           }
 
          return *this;
    }
             
               
  String operator+( const String& rhs ) {
             String N3;
             N3.size = size + rhs.size;
             N3.str = new char[N3.size+1];
             strcpy( N3.str, str );
             strcat( N3.str, rhs.str );
             return N3;
}
         
 
  void ShowStr() { cout << str << endl; }
  void ShowSize() { cout << size << endl; }
 
};
 
int main()
{
    String N1("hello");
    String N2("World");
    String N3("Its Me");
    String N4 = N1 + N2 + N3;
    N4.ShowStr();
    N4.ShowSize();
    system("pause");
    return 0;
}


Ошибка в прикреплении. В чем я ошибся?
Миниатюры
Ошибка после перегрузки оператора +  
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
05.08.2017, 17:13
Ответы с готовыми решениями:

Ошибка перегрузки оператора
Здравствуйте уважаемые программисты, при созданиии проэкта возникает ошибка In function 'int...

Ошибка из книги оператора перегрузки
// Листинг 10.10. // Возвращение безымянного временного объекта #include &lt;string&gt; #include...

Ошибка при реализации перегрузки оператора <<
Добрый день. Прошу помощи. Имеется такой класc. class DList { ... public: ... void...

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

25
Модератор
Эксперт С++
13496 / 10751 / 6406
Регистрация: 18.12.2011
Сообщений: 28,688
05.08.2017, 17:31 2
C++
1
2
3
4
5
6
7
8
9
10
11
12
String( const char* outStr ) 
{ 
    size = strlen(outStr);
    str = new char[size+1];
    strcpy( str, outStr );
}
 
String( const String& rhs ) { 
    size = rhs.size;
    str = new char[size+1];
    strcpy( str, rhs.str );
}
C++
1
2
3
4
5
6
7
8
9
10
11
String& operator=( const String& rhs ) {
 
    if ( this != &rhs ) 
    {
        delete [] str; 
        size = rhs.size;
        str = new char[size+1];
        strcpy( str, rhs.str );
    }
    return *this;
}
1
Заблокирован
05.08.2017, 18:57 3
Цитата Сообщение от zss Посмотреть сообщение
strcpy( str, outStr );
Ну и что будет при outStr = 0?
0
495 / 209 / 70
Регистрация: 27.05.2016
Сообщений: 557
05.08.2017, 21:00 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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <iostream>
#include <cstring>
#include <utility>
 
using namespace std;
 
class String
{
    char* str = nullptr;
    size_t size = 0;
 
public:
 
    String() = default;
 
    explicit String(const char* other_str)
    {
        if (other_str)
        {
            size = strlen(other_str);
            str = new char[size + 1];
            strcpy(str, other_str);
        }
    }
 
    String(const String& rhs)
    {
        if (rhs.size)
        {
            size = rhs.size;
            str = new char[size + 1];
            strcpy(str, rhs.str);
        }
    }
 
    String(String&& rhs) noexcept
    {
        str = rhs.str;
        size = rhs.size;
 
        rhs.str = nullptr;
        rhs.size = 0;
    }
 
    ~String()  { delete[] str; }
 
    void swap(String& rhs) noexcept
    {
        using std::swap;
        swap(str, rhs.str);
        swap(size, rhs.size);
    }
 
    String& operator =(String&& rhs) noexcept
    {
        if (this != &rhs)
        {
            delete [] str;
            str = rhs.str;
            size = rhs.size;
 
            rhs.str = nullptr;
            rhs.size = 0;
        }
        return *this;
    }
 
    String& operator =(String rhs)
    {
        rhs.swap(*this);
        return *this;
    }
 
    String& operator +=(const String& rhs)
    {
        if (rhs.size)
        {
            size_t new_size = size + rhs.size;
            char* new_str = new char[new_size + 1];
            strcpy(new_str, str);
            strcpy(new_str + size, rhs.str);
            delete [] str;
            str = new_str;
            size = new_size;
        }
        return *this;
    }
 
    void ShowStr() const { cout << str << endl; }
 
    void ShowSize() const { cout << size << endl; }
};
 
const String operator +(const String& lhs, const String& rhs)
{
    return (String(lhs) += rhs);
}
 
//namespace std
//{
//    template <>
//    void swap(String& lhs, String& rhs) noexcept (true)
//    {
//        lhs.swap(rhs);
//    }
//}
 
int main()
{
    String N1("hello");
    String N2("World");
    String N3("Its Me");
    String N4 = N1 + N2 + N3;
    N4.ShowStr();
    N4.ShowSize();
}
Добавлено через 2 минуты
Сразу задам вопрос - почему код не компилируется со специализацией для std::swap?
0
Заблокирован
05.08.2017, 21:20 5
Цитата Сообщение от notAll Посмотреть сообщение
Сразу задам вопрос - почему код не компилируется со специализацией для std::swap?
Код
error: no function template matches function template specialization 'swap'

note: candidate template ignored: requirement 'is_move_assignable<String>::value' was not satisfied [with _Tp = String]
Добавлено через 6 минут
Цитата Сообщение от notAll Посмотреть сообщение
const String operator +
Зачем const?
0
495 / 209 / 70
Регистрация: 27.05.2016
Сообщений: 557
05.08.2017, 21:24 6
Цитата Сообщение от Tree depth Посмотреть сообщение
Зачем const?
C++
1
N1 + N2 = N3;
0
Заблокирован
05.08.2017, 21:27 7
notAll

C++
1
2
3
4
String N1, N2, N3;
...
// String& operator =(String rhs);
N1 = N2 + N3; // прощай, move-конструктор аргумента operator=(), я возвращаю const String из operator+
1
495 / 209 / 70
Регистрация: 27.05.2016
Сообщений: 557
05.08.2017, 21:28 8
Цитата Сообщение от Tree depth Посмотреть сообщение
note: candidate template ignored:
Это означает что компилятор считает что в std есть более подходящая swap для String. А как же тогда моя специализация?
0
Заблокирован
05.08.2017, 21:30 9
Цитата Сообщение от notAll Посмотреть сообщение
Это означает что компилятор считает что в std есть более подходящая swap для String.
Нет.

Цитата Сообщение от notAll Посмотреть сообщение
А как же тогда моя специализация?
Зачем вообще специализация? Перегрузка не устраивает?

Добавлено через 1 минуту
Цитата Сообщение от notAll Посмотреть сообщение
N1 + N2 = N3;
Это можно запретить другим путём, не мешая move-конструктору.
0
495 / 209 / 70
Регистрация: 27.05.2016
Сообщений: 557
05.08.2017, 21:32 10
Цитата Сообщение от Tree depth Посмотреть сообщение
Зачем вообще специализация?
Любой новый не шаблонный разрабатываемый тип должен иметь специализацию для std::swap. Это нужно, как минимум, для более эффективной работы с контейнерами.
0
Заблокирован
05.08.2017, 21:36 11
Цитата Сообщение от notAll Посмотреть сообщение
Любой новый не шаблонный разрабатываемый тип должен иметь специализацию для std::swap. Это нужно, как минимум, для более эффективной работы с контейнерами.
Чем
Цитата Сообщение от Tree depth Посмотреть сообщение
Перегрузка не устраивает?
Добавлено через 2 минуты
Т.е. даже не перегрузка std::swap, а определение swap как friend внутри класса String.
0
495 / 209 / 70
Регистрация: 27.05.2016
Сообщений: 557
05.08.2017, 21:41 12
Цитата Сообщение от Tree depth Посмотреть сообщение
Чем перегрузка не устраивает?
Нужно для страховки от программистов, которые будут писать явно std::swap(String_obj_1, String_obj_2) вместо классического:
C++
1
2
using std::swap;
swap(String_obj_1, String_obj_2);
Да, и обычную перегрузку для swap тоже надо добавлять, тут я согласен.
0
Заблокирован
05.08.2017, 21:48 13
Цитата Сообщение от notAll Посмотреть сообщение
Нужно для страховки от программистов, которые будут писать явно std::swap(String_obj_1, String_obj_2)
Если ничего не делать, то у них это не скомпилируется по той же причине, по которой не получается сделать специализацию (потому что нет подходящего шаблона для специализации):
Код
error: no matching function for call to 'swap'
    std::swap(N1, N2);
note: candidate template ignored: requirement 'is_move_assignable<String>::value' was not satisfied [with _Tp = String]
swap(_Tp& __x, _Tp& __y) _NOEXCEPT_(is_nothrow_move_constructible<_Tp>::value &&

Если в std запихать перегрузку:
C++
1
2
3
namespace std {
    void swap(String& s1, String& s2) noexcept { s1.swap(s2); }
}
а не “специализацию", то выберется перегрузка.
0
495 / 209 / 70
Регистрация: 27.05.2016
Сообщений: 557
05.08.2017, 21:54 14
А, все, нашел причину. Вся проблема была из за того что один из операторов присваивания был без спецификатора noexcept.

Добавлено через 1 минуту
Цитата Сообщение от Tree depth Посмотреть сообщение
Если в std запихать перегрузку
Тут такое дело - в std нельзя добавлять свои перегрузки функций. Только полные специализации.
0
Заблокирован
05.08.2017, 21:58 15
Цитата Сообщение от notAll Посмотреть сообщение
А, все, нашел причину.


Так что с const String operator+ делать? move-конструкторы — для хипстеров?
0
495 / 209 / 70
Регистрация: 27.05.2016
Сообщений: 557
05.08.2017, 22:01 16
И еще поправить вот так:
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
String& operator =(String&& rhs) noexcept
    {
        if (this != &rhs)
        {
            delete [] str;
            str = rhs.str;
            size = rhs.size;
 
            rhs.str = nullptr;
            rhs.size = 0;
        }
        return *this;
    }
 
    String& operator =(const String& rhs)
    {
        String temp(rhs);
        temp.swap(*this);
        return *this;
    }
 
namespace std
{
    template <>
    void swap(String& lhs, String& rhs) noexcept (noexcept(lhs.swap(rhs)))
    {
        lhs.swap(rhs);
    }
}
Добавлено через 2 минуты
Цитата Сообщение от Tree depth Посмотреть сообщение
Так что с const String operator+ делать
Походу надо убирать const чтобы мув-семантика не страдала.
0
Заблокирован
05.08.2017, 22:02 17
notAll, считаешь, что ради запихивания специализации в std стоит отказаться от copy/move-and-swap idiom и плодить кучу операторов присваивания?

Добавлено через 45 секунд
Цитата Сообщение от notAll Посмотреть сообщение
Походу надо убирать const чтобы мув-семантика не страдала.
А как N1 + N2 = N3 запретить?
0
495 / 209 / 70
Регистрация: 27.05.2016
Сообщений: 557
05.08.2017, 22:37 18
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
String& operator =(String&& rhs) & noexcept
    {
        if (this != &rhs)
        {
            delete [] str;
            str = rhs.str;
            size = rhs.size;
 
            rhs.str = nullptr;
            rhs.size = 0;
        }
        return *this;
    }
 
    String& operator =(const String& rhs) &
    {
        String temp(rhs);
        temp.swap(*this);
        return *this;
    }
Добавлено через 24 минуты
Оказывается что
C++
1
2
3
String& operator =(String rhs) //for copy-and-swap
 
std::cout << std::is_nothrow_move_assignable<String>::value << "\n"; // false
C++
1
2
3
4
String& operator =(String&& rhs) noexcept
String& operator =(String rhs) //for copy-and-swap
 
std::cout << std::is_nothrow_move_assignable<String>::value << "\n"; // false
C++
1
2
3
4
String& operator =(String&& rhs) noexcept
String& operator =(const String& rhs) //for copy-and-swap with temporary object
 
std::cout << std::is_nothrow_move_assignable<String>::value << "\n"; // true
И писать два оператора присваивания все равно придется.
0
Заблокирован
05.08.2017, 23:24 19
Цитата Сообщение от notAll Посмотреть сообщение
И писать два оператора присваивания все равно придется.
C++
1
2
3
String& operator =(String rhs) noexcept //for copy-and-swap
 
std::cout << std::is_nothrow_move_assignable<String>::value << "\n"; // true
Добавлено через 8 минут
Цитата Сообщение от Tree depth Посмотреть сообщение
ради запихивания специализации в std стоит отказаться от copy/move-and-swap idiom и плодить кучу операторов присваивания?
*поправлюсь, на самом деле не нужно отказываться
0
495 / 209 / 70
Регистрация: 27.05.2016
Сообщений: 557
05.08.2017, 23:27 20
Это будет скорее всего обман пользователей так как у нас есть конструктор копий, который может кидать исключение. И обработать теперь этот ексепшин никто не сможет. Так что я бы так не писал.
0
05.08.2017, 23:27
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
05.08.2017, 23:27
Помогаю со студенческими работами здесь

Использование перегрузки оператора +
Есть у меня класс CPoint, с конструктором: CPoint::CPoint(float x, float y) { setX(x);...

Целесообразность перегрузки оператора
Изначально имелся такой вот метод (пусть будет методом класса &quot;A&quot;): //класс &quot;A&quot;, константная...

Friend-функции перегрузки оператора
Всем доброго времени суток =) У меня есть следующий код заголовочного файла: enum month {jan = 1,...

Вопрос по поводу перегрузки оператора +
Всем привет.Подскажите как можно перегрузить оператор + в моем классе? И что лучше вернуть из...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

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