Запрещение функции-члену const изменять массив элементов - PullRequest
3 голосов
/ 18 сентября 2011

Очевидно, что функция-член const по-прежнему может изменять данные, на которые указывает член класса. Вот пример того, что я имею в виду:

class MyClass
{
public:
  MyClass();
  int getSomething() const;
private:
  int* data;
};

// ... data = new int[10];, or whatever

int MyClass::getSomething() const
{
  data[4] = 3; // this is allowed, even those the function is const
  return data[4];
}

Я бы предпочел, если бы это было запрещено. Как определить «данные», чтобы «getSomething () const» не мог их изменить? (но так, чтобы неконстантные функции могли изменять его.) Есть ли какая-то «лучшая практика» для этого? Возможно, std :: vector?

Ответы [ 3 ]

7 голосов
/ 18 сентября 2011

В функции-члене const тип data изменяется с int* на int *const:

int * const data;

, что означает, что в функции-члене const указатель равен const, а не сами данные, на которые указывает указатель. Таким образом, вы не можете сделать следующее:

data = new int[100]; //error 

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

data[0] = 100; //ok

Потому что при изменении содержимое не меняется указатель . data указывает на то же место в памяти.

Если вы используете std::vector<int>, тогда вы можете достичь того, что вы хотите. Фактически, вектор решает эту проблему, наряду с проблемами управления памятью, поэтому используйте ее:

class MyClass
{
public:
  MyClass();
  int getSomething() const;
private:
  std::vector<int> data;
};

MyClass::MyClass() : data(10) {}  //vector of size 10

int MyClass::getSomething() const
{
  data[4] = 3; // compilation error - this is what you wanted.
  return data[4];
}

Избегайте не-RAII дизайна столько, сколько сможете. RAII - превосходное решение проблем управления памятью. Здесь, с его помощью, вы добиваетесь того, чего хотите. Прочитайте это:

4 голосов
/ 18 сентября 2011

Причина, по которой вы должны использовать std :: vector, заключается в том, что вы хотите хранить коллекцию целых, а не указатель на int, так почему бы не использовать его?

Это также решит вашу проблему с константой.

Вот как это работает: объявление метода const сделает всех членов класса const. В вашем случае это означает, что в области действия метода ваш член data станет постоянным указателем на int. Это означает, что вы можете изменить значение int (также означающее элементы массива), если data указывает на то же место. Используя std::vector, данные становятся константными std::vector, для которых вы можете вызывать только константные функции. Так что да, вы должны использовать std::vector.

4 голосов
/ 18 сентября 2011

Нет способа делать то, что ты хочешь. Ваша постоянная функция-член не может изменить значение данных (адрес, на который она указывает), но нет ничего в том, чтобы не изменять содержимое, на которое она указывает, как вы уже заметили. Использование std::vector помогло бы, так как внутри функции-члена const вы фактически имели бы вектор const, не имея возможности вызывать какие-либо из его изменяемых функций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...