exponenta event banner

Возврат дескриптора non const в инкапсулированный элемент данных

Метод возвращает указатель или ссылку на внутренний элемент объекта

Описание

Этот дефект возникает в следующих случаях:

  • Метод класса возвращает дескриптор элементу данных. Дескрипторы включают указатели и ссылки.

  • Метод более доступен, чем элемент данных. Например, метод имеет спецификатор доступа public, но элемент данных private или protected.

Риск

Спецификатор доступа определяет доступность элемента класса. Например, член класса, объявленный с помощью private невозможно получить доступ к спецификатору доступа вне класса. Поэтому функции, не относящиеся к члену, не связанные с другом, не могут изменять член.

Когда метод класса возвращает дескриптор менее доступному члену данных, доступность элемента изменяется. Например, если public метод возвращает указатель на private член данных, член данных фактически не private больше. Функция, не являющаяся членом, не являющаяся другом, вызывающая public метод может использовать возвращенный указатель для просмотра и изменения элемента данных.

Кроме того, при назначении указателя элементу данных объекта другому указателю при удалении объекта второй указатель может быть оставлен висящим. Второй указатель указывает на часть объекта, которая больше не существует.

Зафиксировать

Одно из возможных исправлений состоит в том, чтобы избежать возврата дескриптора элементу данных из метода класса. Возвращает элемент данных по значению, чтобы вернуть копию элемента. Изменение копии не изменяет элемент данных.

Если необходимо вернуть дескриптор, используйте const квалификатор с возвращаемым типом метода, так что дескриптор позволяет просматривать, но не изменять элемент данных.

Примеры

развернуть все

#include <string>
#define NUM_RECORDS 100

struct Date {
    int dd;
    int mm;
    int yyyy;
};


struct Period {
    Date startDate;
    Date endDate;
};

class DataBaseEntry {
private:
    std::string employeeName;
    Period employmentPeriod;
public:
    Period* getPeriod(void);
};

Period* DataBaseEntry::getPeriod(void) {
    return &employmentPeriod;
}


void use(Period*);
void reset(Period*);

int main() {
    DataBaseEntry dataBase[NUM_RECORDS];
    Period* tempPeriod;
    for(int i=0;i < NUM_RECORDS;i++) {
        tempPeriod = dataBase[i].getPeriod();
        use(tempPeriod);
        reset(tempPeriod);
    }
    return 0;
}

void reset(Period* aPeriod) {
       aPeriod->startDate.dd = 1;
       aPeriod->startDate.mm = 1;
       aPeriod->startDate.yyyy = 2000;
}

В этом примере: employmentPeriod является private в класс DataBaseEntry. Таким образом, он защищен от модификации функциями, не являющимися членами группы и не являющимися друзьями. Однако возврат указателя на employmentPeriod разрывает эту инкапсуляцию. Например, функция, не являющаяся членом reset изменяет элемент startDate из employmentPeriod.

Исправление: Возврат элемента по значению

Одной из возможных корректировок является возврат элемента данных. employmentPeriod по значению вместо указателя. Изменение возвращаемого значения не изменяет элемент данных, поскольку возвращаемое значение является копией элемента данных.

#include <string>
#define NUM_RECORDS 100

struct Date {
    int dd;
    int mm;
    int yyyy;
};


struct Period {
    Date startDate;
    Date endDate;
};

class DataBaseEntry {
private:
    std::string employeeName;
    Period employmentPeriod;
public:
    Period getPeriod(void);
};

Period DataBaseEntry::getPeriod(void) {
    return employmentPeriod;
}


void use(Period*);
void reset(Period*);

int main() {
    DataBaseEntry dataBase[NUM_RECORDS];
    Period tempPeriodVal;
    Period* tempPeriod;
    for(int i=0;i < NUM_RECORDS;i++) {
        tempPeriodVal = dataBase[i].getPeriod();
        tempPeriod = &tempPeriodVal;
        use(tempPeriod);
        reset(tempPeriod);
    }
    return 0;
}

void reset(Period* aPeriod) {
       aPeriod->startDate.dd = 1;
       aPeriod->startDate.mm = 1;
       aPeriod->startDate.yyyy = 2000;
}

Информация о результатах

Группа: Объектно-ориентированная
Язык: C++
По умолчанию: Откл.
Синтаксис командной строки: BREAKING_DATA_ENCAPSULATION
Воздействие: среднее
CWE ID: 375, 767
Представлен в R2015b