Какой будет вариант использования для функции, возвращающей константный указатель (например, int * const)? - PullRequest
2 голосов
/ 19 марта 2012

Название самоочевидно, но я все равно приведу пример.

int sum(int a, int b){
    return a + b;
}

Мы могли бы переписать его как

int sum(const int a, const int b){
    return a + b;
}

Но как насчет возврата const int? Это полезно в любом случае?

const int sum(const int a, const int b){
    return a + b;
}

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

Хорошо, я не совсем поняла, в теле вопроса. Подумайте о функции суммы, которая работает аналогично сборке add:

int *sum(int *a, int b){
    *a += b;
    return a;
}

Добавьте const к параметрам:

int *sum(int * const a, const int b){
    *a += b;
    return a;
}

А как насчет возврата const тоже? Есть ли причина для этого?

Ответы [ 4 ]

3 голосов
/ 19 марта 2012

Я могу рассматривать это только как заявление о намерениях.

Нечто большее в смысле - if you get this value, you shouldn't need to change it, больше, чем don't change this value.

Это действительно достигаетсяничего, кроме намерения, так как вы в любом случае можете изменить значение: http://ideone.com/Mf8Ge

2 голосов
/ 20 марта 2012

Есть много ситуаций, в которых вы можете вернуть константный указатель или константный объект.Я не могу представить себе реальную ситуацию, когда вы хотите вернуть примитивный тип как const.

Я не уверен, какой у вас вопрос, в названии, о котором вы говорите int* const, но в примере кода у вас есть const int.

Некоторые примеры (на C ++) следуют для различных комбинаций const и T*.

Указатель на const (примитивтип)

const int* someFuncion();

У вас есть указатель на константу, это означает, что вы можете изменить указатель, но вы не можете изменить указанный объект / значение.Обратите внимание, что someFunction() не должен возвращать указатель (const или нет) на переменную, выделенную в стеке.Я предполагаю, что указатель действителен.Например:

const int* value = someFunction();

// Next line is valid, value will hold a new pointer
value = anotherFunction(); 

// Next line is not valid, pointed value cannot be changed
*value = 10;

Указатель на const (объект)

const T* someFunction();

У вас есть указатель на константу.Это означает, что вы можете изменить указатель так, чтобы он указывал на другой объект, но вы не можете изменить состояние указанного объекта.Это не означает, что вы не можете использовать этот объект, только то, что объект является const, тогда вы можете использовать только его методы, помеченные как const, читать его поля и записывать его изменяемые поля.Константный метод определяется как:

void method() const;

Он может иметь любой тип возвращаемого значения и любой параметр, суть в том, что он помечен модификатором const.Это означает, что он не изменит состояние объекта (опять-таки, за исключением mutable объектов).

Теперь приведен пример с T, объявленным как:

class T
{
public:
 void dump() const
 {
  // Dump the value to console, for example
 }

 void increaseValue()
 {
  ++m_value;
 }

private:
 int m_value;
};

Представьте себенаписать следующий код:

const T* value = someMethod();

// Next line is valid, value will hold a new pointer
value = anotherMethod();

// Next line is not valid, we cannot change the object state
value->increaseValue();

// Next line is valid, we do not change the object state
value->dump();

Указатель константы (тип примитива)

int* const someFunction();

У вас есть указатель константы, это означает, что вы можете изменить указанное значение, но вы не можете назначить другую ячейку памятик самому указателю.Например:

int* const value = someFunction();

// Next line is not valid, value cannot be changed
value = anotherFunction();

// Next line is valid, you can change the variable pointed by value
*value = 10;

Указатель константы (объект)

T* const someFunction();

У вас есть указатель константы, это означает, что вы можете изменить состояние указанного объекта, но вы не можете назначить другую ячейку памяти длясам указательНапример:

T* const value = someFunction();

// Next line is not valid, value cannot be changed
value = anotherFunction();

// Next lines are both valid, we can do whatever we want with the object
value->increaseValue();
value->dump();

Указатель константы на постоянную

const int* const someFunction();

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

Примечания

Модификатор const не ограничен для использования с указателями и возвращаемым значением функций.Например:

// PI value cannot be changed
const int PI = 3.14f;

// I have a pointer to a constant value
const* int pPI = Π

// I have a constant pointer to a constant value, note that
const* int const pPI2 = Π

Помните, что модификатор const всегда можно удалить, используя приведение в стиле C или const_cast.

Выводы

Итак,Возвращаясь к вашему вопросу, полезна ли функция с const int возвращаемым значением?

Если это указатель, мой ответ - да , даже если его можно удалить с помощью приведения:цель const состоит в том, чтобы сообщить намерения (избавляя вас от глупых ошибок, которые трудно найти), чтобы больше вашей функции сообщалось и лучше ее использовали.Обновляя это из вашего последнего примера, я отвечу да , используйте const везде, где это возможно.Тот, кто назовет ваш код, поблагодарит вас (и вы сделаете это сами).

Если это просто const int (или другой примитивный тип), может быть очень редко вы пишете что-то подобное,Очень часто они являются просто промежуточными результатами длинных вычислений, тогда их бесполезно объявлять как const (примитивные типы не изменятся, но будут объединены для создания нового значения).Однако обратите внимание, что если имеет смысл объявить их как const, то вы должны сделать это.Я предполагаю, что более распространено видеть постоянный тип примитива, объявленный как локальная переменная (опять же, чтобы убедиться, что он не будет изменен по ошибке)Например:

// This local variable cannot be modified
const int rate = (calculateX() + calculateY()) / calculateRateFactor();

Или в функциях, почему бы и нет?Если вы всегда используете это правило (const, если его не нужно менять), вы увидите на лету, когда параметр не const, тогда вы поймете, что вы его где-то измените (возможно, смаленький, скрытый, симпатичный ++ на самом правильном символе вашего экрана).

// With this prototype I'm sure I won't change a or b by mistake inside
// the function body.
int someFunction(const int a, const int b);

Для объектов, я думаю, еще более распространенным является использование модификатора const (поскольку тип возвращаемого значения const T имеет смысл очень часто), например:

// This object cannot be changed, just moved all around
const order* getNextOrderToStore();

Тема не закончена, конечно, из-за псевдонимов, непостоянных переменных, перегрузки операторов и различий между C и C ++ ...

1 голос
/ 19 марта 2012

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

0 голосов
/ 19 марта 2012

Вызывающий должен будет скопировать возврат const в const lvalue.

Нет, это вообще не будет.На самом деле, он может никогда не скопировать его.Или он может скопировать его в изменяемое значение lvalue.

Нет смысла в const значениях, никогда не было и никогда не будет.

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