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

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

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 1, средняя оценка - 5.00
zss
Модератор
Эксперт С++
6879 / 6441 / 2155
Регистрация: 18.12.2011
Сообщений: 16,930
Завершенные тесты: 1
#1

Распространенные ошибки - C++

21.09.2014, 17:33. Просмотров 72318. Ответов 65
Метки нет (Все метки)

Оглавление

Ошибки этапа компиляции
Программа не компилируется или компилируется с предупреждениями.
  1. Попытка модифицировать константу через указатель
  2. Неправильное понятие приведения
  3. Лишняя точка с запятой
  4. Отсутствие точки с запятой после определения классового типа
  5. Отсутствие возврата значения из функции
  6. Использование комментариев в #define
  7. Компилятор не находит iostream.h
  8. Внутри switch ошибка Case bypasses initialization of a local variable
  9. Передача двумерных массивов и указателей в функцию
  10. Не удается открыть файл stdafx.h
  11. Ошибка "unresolved external symbol _WinMain@16"
  12. Ошибка "This function or variable may be unsafe"
Ошибки этапа выполнения
Программа прекращает работу с сообщением об ошибке
  1. Выделение памяти без дальнейшего освобождения или неверное освобождение
  2. Возврат ссылки/указателя на локальную переменную
  3. Использование неинциализированной переменной
  4. Выход за пределы массива
  5. Ошибки при использовании функции scanf()
  6. Работа с локальной копией объекта, вместо работы с самим объектом
  7. Интерпретация одиночного char символа как символьной строки
  8. Ошибка преобразования: type ** в const type **
Неправильное поведение программы на этапе исполнения
Программа исполняется, но не так, как хотелось.
  1. Неожиданное закрытие окна
  2. "Неожиданное" целочисленное деление в арифметических выражениях
  3. Ошибки в логических выражениях
  4. Лишняя точка с запятой
  5. switch без break
  6. Сравнение вещественных чисел при вычислениях
  7. Сравнение char массивов
  8. Использование чисел, записанных в других системах счисления
  9. Проверки на принадлежность значения определенному интервалу
  10. Неверный аргумент тригонометрических функций
  11. Сравнение знаковой переменной с беззнаковой
  12. Использование запятой для отделения дробной части
  13. Забытое выделение тела цикла for, while и операторов if else
  14. Определение размера массива, переданного в качестве аргумента функции
  15. Порядок вычисления аргументов при вызове функции
  16. Некорректное использование логических переменных
  17. Вычисленное значение косинуса не совпадает с ожидаемым
  18. Локальная переменная экранирует переменную с таким же именем из вышестоящей области видимости
  19. Неправильное использование memset
Алгоритмические ошибки
Ошибки, допущенные при разработке алгоритма
  1. Двойная перестановка строк или элементов массива
  2. Использование символа цифры вместо числа
Ошибки ввода-вывода
  1. Оставление символа '\n' в потоке ввода
  2. Ошибки при использовании функции scanf()
  3. При работе с fgetc чтение файла обрывается при достижении буквы 'я'
  4. При считывании из файла последний элемент читается дважды
Ошибки, связанные с отклонением от стандарта языка
  1. Неверный тип функции main()

Ошибки проектирования АТД (классов).
  1. Вызов виртуальной функции из конструктора
  2. Отсутствие точки с запятой после определения класса/структуры
  3. Неверный вызов конструктора базового класса из конструктора производного
  4. Неверный порядок при инициализации
  5. Нарушение правила ТРЕХ.
  6. Отсутствие виртуального деструктора в базовом классе
  7. Неправильное обращение к конструктору по умолчанию
  8. Не очевидные моменты с вызовом конструктора базового класса
  9. Неявно объявленный конструктор по умолчанию
  10. Перегрузка оператора >>
Ошибки при использовании STL контейнеров
  1. Невалидные ссылки/указатели, при перемещении объектов
  2. Ошибки связанные с итераторами (кэширование размера контейнера)
  3. Ошибки связанные с итераторами (удаление элементов по итератору в циклах)
  4. Ошибки связанные с итераторами (префикс-постфиксные инкременты при удалении элементов в цикле)
27
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
21.09.2014, 17:33
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Распространенные ошибки (C++):

Вывести самые распространенные мужские и женские имена - C++
Имеется массив записей о студентах, каждая из которых включает поля: фамилия, имя, отчество, пол, возраст, курс. Разработать программу,...

Вывести самые распространенные женские и мужские имена - C++
Помогите решить задачу пожалуйста! Написать программу, которая формирует файл записей данной структуры Type Student=Record ...

Найти ошибки в коде и исправить эти ошибки (Наследование) - C++
Вот в общем 3 файла, изучаю наследование на примере односвязного и двусвязного списков: list.h (inline) #pragma once class list...

Найти ошибки в коде и исправить эти ошибки - C++ - C++
Судя по вываливающейся ошибки, идет двойное освобождение памяти. У самого не получается отловить откуда. A.h #pragma once ...

Найти ошибки в коде и исправить эти ошибки - C++
Есть у меня вот такой код: #include <iostream> using namespace std; class A{ private: int* a; size_t size_; ...

Распространенные ошибки - C (СИ)
Оглавление Ошибки этапа компиляции (В процессе компиляции выдается либо сообщение об ошибке, либо предупреждение) - Попытка...

65
KOPOJI
Почетный модератор
Эксперт HTML/CSSЭксперт PHP
16711 / 6633 / 433
Регистрация: 12.06.2012
Сообщений: 19,880
Завершенные тесты: 1
24.09.2014, 11:52 #16
Использование чисел, записанных в других системах счисления.
Может показаться, что значения следующих двух переменных одинаковые:
C++
1
2
    int x = 123;
    int y = 0123;
Однако это совсем не так. Первое число (123) записано в десятичной системе счисления. Т.к. по умолчанию (и чаще всего) мы работаем с десятичной системой счисления, то x так и будет равен 123.
Второе же число (0123) записано в восьмеричной системе счисления и при переводе в десятичную будет равно 83, а не 123. Если вы работаете с десятичной системой счисления, то не добавляйте цифру "0" перед числом.


Проверка на принадлежность значения определенному интервалу.
Иногда при проверке принадлежности значения переменной определенному интервалу можно увидеть нечто подобное
C++
1
    if ( 0 <= x <= 10 )
Несмотря на кажущуюся логичность, этот код не проверяет на то, что x лежит между 0 и 10.
Если разбить на шаги, то они будут следующими:
Т.к. оператор сравнения <= левоассоциативен (т.е., выполняется слева направо), то первым шагом будет сравнение 0 и x
1. 0 <= x. Результат сравнения - true или false, которые будут преобразованы в 1 или 0 соответственно.
2. сравниваем полученный результат с 10. 10 больше и 1, и 0. Следовательно, условие всегда истинно.
В общем случае, можно сказать, что при сравнении подобным образом, если последнее число (в примере это число 10) больше или равно 1, то условие всегда истинно.
Проверку на принадлежность интервалу правильно записывать с помощью логического оператора И.
C++
1
    if ( 0 <= x && x <= 10 )
Ошибкой также является использование запятой, вместо логического И
C++
1
    if ( 0 <= x , x <= 10 )
В этом случае, значения выражения 0 <= x никак не используется. Результатом будет значение выражения x <= 10.

Иногда вместо логического И используют логическое ИЛИ.
Выражение
C++
1
    if ( 0 <= x || x <= 10 )
не означает, что значение x лежит между 0 и 10. Это может быть вообще любое число. Почему так происходит:
1. Проверяем первое условие. Если x больше или равен нулю, то истина. Значит, любое положительное значение уже истина.
2. Если первое условие не выполнилось, то проверяем второе условие. Любое отрицательное число (а предыдущее условие могло не пройти только отрицательное значение) меньше 10, значит, условие тоже истинное.
Следовательно, условие всегда истинное.
3
KOPOJI
Почетный модератор
Эксперт HTML/CSSЭксперт PHP
16711 / 6633 / 433
Регистрация: 12.06.2012
Сообщений: 19,880
Завершенные тесты: 1
24.09.2014, 12:11 #17
Отсутствие возврата значения из функции

Например, следующая функция
C++
1
2
3
4
5
int f( int x )
{
    if ( x == 10 )
        return 1;
}
является ошибочной: в случае невыполнения условия возврата из функции нет никакого.
Для избежания этого из функции обязательно должен быть возврат, вне зависимости от выполнения или невыполнения условия.
C++
1
2
3
4
5
6
int f( int x )
{
    if ( x == 10 )
        return 1;
    return 0;
}
Компилятор может выдать предупреждающее сообщение:
1>d:\current\cpp\test\test.c(8) : warning C4715: f: значение возвращается не при всех путях выполнения
Для этого надо установить соответствующий уровень предупреждений компилятора.
В Visual Studio это делается через команду меню:
Проект -> Свойства -> Свойства конфигурации -> С/С++ -> Общие -> Уровень предупреждений -> Уровень 4 (/W4).

Реальный пример - функция поиска позиции первого вхождения символа в строку.
C++
1
2
3
4
5
6
7
int indexOf( const char * str, const char c )
{
    for ( int i = 0; str[i]; ++i )  // пробегаемся по строке
        if ( str[i] == c )          // если текущий символ - искомый
            return i;               // то возвращаем индекс этого символа
    return -1;                      // если цикл прошелся и возврата не выполнено (символ не найден), возвращаем -1
}
2
zss
Модератор
Эксперт С++
6879 / 6441 / 2155
Регистрация: 18.12.2011
Сообщений: 16,930
Завершенные тесты: 1
24.09.2014, 12:32  [ТС] #18
Оставление символа '\n' в потоке ввода:
C++
1
2
3
4
cout << "введите n:";
int n; cin >> n;    // вводится число после нажатия Enter
cout << "введите символ:";
char c; cin.get(c); // хотим ввести символ из новой строки, но вместо него вводится '\n'
C++
1
2
3
4
cout << "введите n:";
int n; cin >> n;    // вводится число после нажатия Enter
cout << "введите строку:";
char c[100]; cin.getline(c,100);    // хотим ввести новую строку, но вводится пустая строка
исправление ошибки
C++
1
2
3
4
5
6
cout << "введите n:";
int n;
(cin >> n).get();   // вводим число и пропускаем один символ
cout << "введите символ:";
char c;
cin.get(c);         // вводится символ на новой строке ( !!!  '\n' второй строки еще не прочитали).
Вместо cin.get() можно просто пропустить символы:
C++
1
2
cin.ignore( k, '\n' );                  // k -  пропускаемое к-во символов,  параметр '\n' можно опускать 
cin.ignore( cin.rdbuf()->in_avail() );  // пропустить все оставшиеся символы
Можно также в цикле прочитать оставшиеся символы
C++
1
while ( cin.get() != '\n' );
Третий способ - синхронизация ввода с помощью cin.sync():
C++
1
2
3
4
5
6
7
8
cout<<"введите n:";
int n;
cin >> n;
cin.sync(); // вводим число и сбрасываем остаток строки
cout << "введите символ:";
char c;
cin >> c;
cin.sync(); // вводим символ на новой строке и тоже сбрасываем остаток строки.
В общем, возможности большие. Главное помнить об этой проблеме!
15
zss
Модератор
Эксперт С++
6879 / 6441 / 2155
Регистрация: 18.12.2011
Сообщений: 16,930
Завершенные тесты: 1
24.09.2014, 12:35  [ТС] #19
Выход за пределы массива
C++
1
2
3
    int arr[5] = { 1, 2, 3, 4, 5 };
    for ( int i = 1;  i <= 5; ++i )
        printf( "%d\n", arr[i] ); // выведет 2 3 4 5 и ... всё что угодно
Индексы массивов в C++ начинаются с нуля. Для массива из N элементов допустимые индексы лежат в диапазоне [0..N-1]. Чтение или запись информации вне выделенной памяти приводит к неопределенному поведению программы.

Также часто встречается выход за пределы массива в строках в стиле C из-за отсутствии терминального нуля:
C++
1
2
3
4
char str[2] = { 'a', 'b' };
cout << str;                                // результат вывода непредсказуем, т.к. неизвестно сколько символов надо выводить
for ( int i = 0; i < strlen( str ); i++ )   // не известно, что вернет strlen()
     str[i] = 'x';                          // соответственно неизвестно к каким элементам массива обратимся.
Исправленный вариант
C++
1
2
3
4
char str[3] = { 'a', 'b', 0 };              // или char str[3] = "ab";
printf( "%s", str );                        // вывод ab
for ( int i = 0; i < strlen( str ); i++ )   // strlen() возвратит 2
    str[i] = 'x';                           // в массиве окажется строка "xx"
2
zss
Модератор
Эксперт С++
6879 / 6441 / 2155
Регистрация: 18.12.2011
Сообщений: 16,930
Завершенные тесты: 1
24.09.2014, 12:38  [ТС] #20
switch без break
C++
1
2
3
4
5
6
switch( i )
{
    case 0: cout << "zero\n";
    case 1: cout << "one\n";
    default: cout << "other\n"; 
}
При i равном 0 будет выведено zero one other. При i равном 1 будет выведено one other. Т.е. без break происходит проваливание к следующей метке. В большинстве случаев, приведенный выше код является ошибочным, но иногда такое поведение может быть задуманным. И в этих случаях следует для очевидности указать в комментарии, что отсутствие break это не ошибка, а явная задумка автора.

Не по теме:

С Вашего позволения внёс небольшую правку (в виде тега inline) в текст. Удалите эту строку после прочтения.

0
BumerangSP
4287 / 1409 / 121
Регистрация: 16.12.2010
Сообщений: 2,941
Записей в блоге: 3
24.09.2014, 12:43 #21
Неверный аргумент тригонометрических функций.
Очень часто бывают ошибки вроде таких:
C++
1
x = sin( 90 ); // x = 0.893997. Имелось ввиду 90 градусов, а функция sin принимает в радианах.
Решение: перевести в градусы:
C++
1
x = sin( 90 * M_PI / 180 ); // x = 1
3
BumerangSP
4287 / 1409 / 121
Регистрация: 16.12.2010
Сообщений: 2,941
Записей в блоге: 3
24.09.2014, 12:43 #22
Неверный вызов конструктора базового класса из конструктора производного.
Встречаются подобные варианты:
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 A {
public:
    int x;
    A() {
        x = 11;
    }
 
    A( int v ) {
        x = v;
    }
};
 
class B : public A {
public:
    B() {}
    B( int v ) {
        A::A( v );  // такой вызов 
        A();        // или такие
        A::A(); 
    }
};
 
int main()
{
    B b( 1 );
    std::cout << b.x;   // x по прежнему = 11.
}
Решение: использовать списки инициализации.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A {
public:
    int x;
    A(): x( 11 ) {}
    A( int v ) : x( v ) {}
};
 
class B : public A {
public:
    B() {}
    B( int v ) : A( v ) {}
};
 
int main() {
    B b( 1 );
    std::cout << b.x;   // x = 1
}
5
BumerangSP
4287 / 1409 / 121
Регистрация: 16.12.2010
Сообщений: 2,941
Записей в блоге: 3
24.09.2014, 12:43 #23
Сравнение знаковой переменной с беззнаковой.
C++
1
2
3
4
    int x = -5;
    unsigned int y = 100;
    if ( x < y ) // Результат false 
    ...
Знаковое x приводится к беззнаковому, отчего возрастает до UINT_MAX - 4 (UINT_MAX равно (unsigned int)-1).
Решение - не сравнивать такие типы, заранее приводить к одному.
0
zss
Модератор
Эксперт С++
6879 / 6441 / 2155
Регистрация: 18.12.2011
Сообщений: 16,930
Завершенные тесты: 1
24.09.2014, 12:58  [ТС] #24
Вызов виртуальной функции из конструктора
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class B
{
    int value;
    virtual int f() const { return 1; } 
 
public:
    B() { value = f(); }
    int getValue() const { return value; }
};
 
class D : public B
{
    virtual int f() const { return 2; } 
};
 
int main()
{
    D d; 
    cout << d.getValue() << endl; // Выводит 1, а не 2
}
Суть в том, что при создании объекта D, сначала создается базовая часть (класс B), а в конструкторе базового класса ничего о классе D еще не известно, т.к. он еще не создан (и в том числе не заполнена таблица виртуальных функций).
1
MrGluck
Модератор
Эксперт CЭксперт С++
7789 / 4827 / 750
Регистрация: 29.11.2010
Сообщений: 13,182
24.09.2014, 16:21 #25
Использование запятой для отделения дробной части
C++
1
2
double x;
x = 3,2; // ожидаем, что присвоится  3.2, а на самом деле 3
Правильно использовать для таких целей .
C++
1
x = 3.2;
Ошибка является весьма коварной и её сложно заметить при использовании длинных выражений. Максимум, что выдаст компилятор - предупреждение о неиспользуемой переменной при включённом флаге -Wunused-value. Так что старайтесь держать сборку идеально чистой и используйте флаги предупреждений, чтобы суметь поймать данную ошибку.
3
gru74ik
Модератор
Эксперт CЭксперт С++
4350 / 1926 / 208
Регистрация: 20.02.2013
Сообщений: 5,109
Записей в блоге: 22
24.09.2014, 16:59 #26
Забытое выделение тела цикла for, while и операторов if else
В циклах часто используют запись тела цикла без фигурных скобок, при условии, что в качестве тела цикла используется один оператор:
C++
1
2
3
4
5
6
7
8
9
// допустимо и так:
for ( int i = 0; i < n; ++i )
    arr[i] = i * i;
 
// и так:
for ( int i = 0; i < n; ++i )
{
    arr[i] = i * i;
}
Это вводит в заблуждение новичков и они пытаются "запихнуть" в цикл несколько операторов, ограничившись отступами:
C++
1
2
3
for ( int i = 0; i < n; ++i )
    arr[i] = i * i;    // будет выполняться на каждом витке цикла
    std:: cout << "Value of " << i + 1 << " element is " << arr[i];    // выполнится после цикла
Если операторов несколько, то в цикле выполнится только первый, остальные же - только по окончании всех итераций (всех витков в цикле). Поэтому, чтобы добиться задуманного новичок должен был бы написать свой код так:
C++
1
2
3
4
5
for ( int i = 0; i < n; ++i )
{   // оба оператора будут выполняться на каждом витке цикла:
    arr[i] = i * i;
    std:: cout << "Value of " << i+1 << " element is " << arr[i];
}
Во избежание подобных ошибок рекомендуется ставить скобки и в случае одного оператора в теле цикла.
Аналогичная ошибка присутствует и в таком примере (Evg):
C++
1
2
3
4
5
if ( x == 0 )
    if ( y == 2 )
        printf ( "a\n" );
else
    printf ( "b\n" );
Из-за отсутствия скобок, оператор else относится не к первому if, а ко второму.
Скобки устраняют эту ошибку:
C++
1
2
3
4
5
6
7
if ( x == 0 )
{
    if ( y == 2 )
        printf( "a\n" );
} else {
    printf( "b\n" );
}

Не по теме:

gru74ik, с Вашего позволения перенёс объявление переменной i в цикл.

1
BumerangSP
4287 / 1409 / 121
Регистрация: 16.12.2010
Сообщений: 2,941
Записей в блоге: 3
24.09.2014, 20:31 #27
Определение размера массива, переданного в качестве аргумента функции.
C++
1
2
3
4
5
6
7
8
9
int f( int * a ) {
    return sizeof a / sizeof *a;
}
 
int main() {
    int a[] = { 1, 2, 3 };
    std::cout << sizeof a / sizeof *a << '\n';  // 3
    std::cout << f( a );                    // 1
}
Решение: передавать размер массива как параметр функции:
C++
1
2
3
4
5
6
7
int f( int * a, int size ) {
    return size;
}
int main() {
    int a[] = { 1, 2, 3 };
    std::cout << f( a, sizeof a / sizeof *a );      // 3
}
Размер массива можно задать при использовании шаблона
( (предложил ISergey):
C++
1
2
3
4
5
6
7
8
9
#include <iostream>
template <typename T, std::size_t size>
std::size_t arr_size( T(&)[size] ) { return size; }
int  main()
{
    int arr[] = { 1, 2, 3, 4 };
    std::cout << arr_size( arr ) << std::endl;
    return 0;
}
Если массив статический, то размер можно узнать, если передать ссылку на массив
(автор Ilot Ошибки: Неуместная рекурсия при вычислении миноров):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
template <typename T>
int f( T & a ) {
    return sizeof( a ) / sizeof( a[0] );
}
 
int main() 
{
    const int N = 5;
    const int M = 15;
    char a[N];
    std::cout << f( a ) << std::endl;
    char b[M];
    std::cout << f( b ) << std::endl;
    return 0;
}
0
Croessmah
Ушел
13769 / 8019 / 924
Регистрация: 27.09.2012
Сообщений: 19,743
Записей в блоге: 3
Завершенные тесты: 1
26.09.2014, 22:19 #28
Неверный порядок при инициализации
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream> 
 
struct Test
{
    int x;
    int y;
    Test ( int y_ ) : y( y_ ) , x( y * 2 ) {}
};
     
int main() {
    Test t( 10 );
    std::cout << t.x << std::endl;
    std::cout << t.y << std::endl;
}
Неверный порядок при инициализации может стать источником ошибок. В списке инициализации конструктора, инициализация происходит в порядке объявления переменных, а не в порядке, указанном в списке инициализации.
В данном случае, сначала будет инициализирована переменная x, а только потом переменная y.
8
daslex
1290 / 534 / 110
Регистрация: 02.08.2011
Сообщений: 2,756
29.09.2014, 21:27 #29
Работа с локальной копией объекта, вместо работы с самим объектом


C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void foo_create( int * Arr ) {
    Arr = new int [10];
    for ( int i = 0; i < 10; i++ ) Arr[i] = i;
}
 
void foo_delete( int * Arr ) {
    delete [] Arr;
    Arr = NULL;
}
 
int main() {
    int * Ptr;
    foo_create( Ptr );
    for ( int i = 0; i < 10; i++ ) cout << Ptr[i] << "  ";
    foo_delete( Ptr );
    return 0;
}
Здесь ошибка в том, что при вызове функции foo_create в нее передается копия указателя Ptr
(который еще не инициализирован). При выделении памяти, ее адрес помещается в эту копию,
т.е. значение переменной Ptr не изменится.
В результате, после возврата из функции, адрес потеряется и, соответственно, потеряется выделенная память.
__________________________________
Варианты решения проблемы:
1. Передавать в функцию адрес указателя
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
void foo_create( int ** ptr_to_ptr )
{
    *ptr_to_ptr = new int [10];
    for ( int i = 0; i < 10; i++ ) (*ptr_to_ptr)[i] = i;
}
 
void foo_delete( int ** ptr_to_ptr )
{
    delete [] *ptr_to_ptr;
    *ptr_to_ptr = nullptr;
}
 
int main()
{
    int * Ptr;
    foo_create( &Ptr );
    for ( int i = 0; i < 10; i++ ) std::cout << Ptr[i] << "  ";
    foo_delete( &Ptr );
    std::cout  << Ptr <<  std::endl;
}
2. Передавать в функцию сылку на указатель
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
 
void foo_create( int * & Arr )
{
    Arr = new int [10];
    for ( int i = 0; i < 10; i++ ) Arr[i] = i;
}
 
void foo_delete( int * & Arr )
{
    delete [] Arr;
    Arr = nullptr;
}
 
int main()
{
    int * Ptr;
    foo_create( Ptr );
    for ( int i = 0; i < 10; i++ ) std::cout << Ptr[i] << "  ";
    std::cout <<  std::endl;
    foo_delete( Ptr );
    std::cout <<  Ptr << std::endl;
}
6
zss
Модератор
Эксперт С++
6879 / 6441 / 2155
Регистрация: 18.12.2011
Сообщений: 16,930
Завершенные тесты: 1
04.10.2014, 13:25  [ТС] #30
Нарушение правила ТРЕХ.
Правило трёх (также известное как «Закон Большой Тройки» или «Большая Тройка») — правило, гласящее, что если класс или структура определяет один из следующих методов, то они должны явным образом определить все три метода:
1. Деструктор
2. Конструктор копирования
3. Оператор присваивания

Эти три метода являются особыми членами-функциями.
Они автоматически создаются компилятором в случае отсутствия их явного объявления.
Если один из них должен быть определен программистом, то это означает, что версия, сгенерированная компилятором, не удовлетворит потребности класса и для двух других.
Пример:
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
class A
{
private:
    int * x; // указатель на массив
    int n;
 
public:
    A() : x( 0 ), n( 0 ) {}
    A( int N ) : n( N )
    {
        x = new int [N]; // под массив выделяется память - нужен деструктор для ее удаления
        for ( int i = 0; i < N; i++ )
            x[i] = i;
    }
 
    ~A() // Создаем деструктор
    {
        delete [] x;
    }
 
    A( const A & a ) : n( a.n ) //  Обязательный копиконструктор (раз есть деструктор)
    {
        x = new int [a.n];
        for ( int i = 0; i < a.n; i++ )
            x[i] = a.x[i];
    }
 
    A & operator = ( const A & a ) // Обязательный оператор присвоения (раз есть деструктор)
    {
        if ( this == &a ) 
            return *this; // присвоение самому себе, ничего делать не надо
 
        delete [] x;
 
        x = new int [a.n];
        for ( int i = 0; i < a.n; i++ )
            x[i] = a.x[i];
 
        return *this;
    }
 
    A operator + ( A & a ) // слияние массивов 
    {
        A c;
        c.n = this->n + a.n;
        c.x = new int [c.n];
 
        int i = 0;
        for ( ; i < this->n; i++ )
            c.x[i] = this->x[i];
 
        int j = 0;
        for ( ; i < c.n; i++, j++ )
            c.x[i] = a.x[j];
 
        return c; // для передачи по значению используется копиконструктор
    }
};
 
int main()
{
    A a1( 2 ), a2( 3 );
    A a3 = a1 + a2; // используется оператор присвоения
    return 0;
}
Примечание.
Не забывайте и о том, что и конструктор по умолчанию тоже в этом случае не создается.
Правда, при необходимости его вызова компилятор выдаст предупреждающее сообщение:
error C2512: A: нет подходящего конструктора по умолчанию
5
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
04.10.2014, 13:25
Привет! Вот еще темы с ответами:

безопасность и распространенные ошибки - Perl
Тут наткнулся на очень интересные тексты: http://werad.narod.ru/articles/programm6.html http://werad.narod.ru/articles/programm9.html...

.NET 2.x Распространенные ошибки SEO и ASP.NET 2.0 - C# ASP.NET
Здравствуйте, существуют несколько СЕО проблем при использовании ASP.NET, ниже я опишу эти проблемы, нужно найти простое и эффективное...

Самые распространенные строки - Delphi
type Mytype = record name:string; surname:string; end; var Students:Mytype; MyFile:file of Mytype; ...

Вирус блокирует выход на сайт вк и другие распространенные сайты - Удаление вирусов
я чайник поэтому если что то не загрузилось..напишите пожалуйста, и помогите... второй день вожусь с этим. Hosts чистый, drweb выявил один...


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

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

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