Как я могу доверять поведению функций C ++, которые объявляют const? - PullRequest
4 голосов
/ 08 февраля 2009

Это катастрофа C ++, посмотрите пример кода:

#include <iostream>

void func(const int* shouldnotChange)
{
    int* canChange = (int*) shouldnotChange;
    *canChange += 2;
    return;
}


int main() {
    int i = 5;
    func(&i);
    std::cout << i;
    return 0;
}

На выходе было 7!

Итак, как мы можем убедиться в поведении функций C ++, если бы он мог изменять предполагаемый постоянный параметр!?

РЕДАКТИРОВАТЬ: Я не спрашиваю, как я могу убедиться, что мой код работает должным образом, скорее я задаюсь вопросом, как поверить, что чужая функция (например, некоторая функция в некоторой библиотеке DLL) не собираюсь менять параметр или обладает некоторым поведением ...

Ответы [ 8 ]

21 голосов
/ 08 февраля 2009

Исходя из ваших правок, ваш вопрос: «Как я могу доверять сторонним кодам, чтобы они не были глупыми?»

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

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

12 голосов
/ 08 февраля 2009

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

Кроме того, напишите юнит-тестирование, что функция не изменяет свой параметр.

9 голосов
/ 08 февраля 2009

Общее правило в C ++ заключается в том, что язык предназначен для защиты вас от Мерфи , а не Макиавелли . Другими словами, он предназначен для предотвращения случайного изменения программистом обслуживания переменной, помеченной как const, а не для того, чтобы кто-то намеренно ее изменял, что можно сделать разными способами.

7 голосов
/ 08 февраля 2009

Применение в стиле C означает, что все ставки сняты. Это все равно, что сказать компилятору: «Поверь мне, я знаю, это выглядит плохо, но мне нужно это сделать, поэтому не говори мне, что я неправ». Кроме того, то, что вы сделали, на самом деле не определено. Отбрасывание константности и затем изменение значения означает, что компилятор / среда выполнения могут делать все что угодно, включая, например завершить работу вашей программы.

2 голосов
/ 08 февраля 2009

Самый простой способ обеспечить это - просто не передавать указатель:

void func(int shouldnotChange);

Теперь будет сделана копия аргумента. Функция может изменять значение по своему усмотрению, но исходное значение не будет изменено.

Если вы не можете изменить интерфейс функции, вы можете сделать копию значения перед вызовом функции:

int i = 5;
int copy = i
func(&copy);
2 голосов
/ 08 февраля 2009

Единственное, что я могу предложить, - это выделить переменную shouldNotChange со страницы памяти, которая помечена как доступная только для чтения. Это заставит ОС / ЦП выдавать ошибку, если приложение попытается выполнить запись в эту память. Я не очень рекомендую это как общий метод проверки функций, просто как идею, которую вы можете найти полезной.

2 голосов
/ 08 февраля 2009

Не используйте приведения в стиле C в C ++.
У нас есть 4 оператора приведения в C ++ (перечислены здесь в порядке опасности)

  • static_cast <> Safe (когда используется для «преобразования числовых типов данных»).
  • dynamic_cast <> Безопасный (но выдает исключения / возвращает NULL)
  • const_cast <> Опасно (при удалении const).
  • static_cast <> Очень опасно (когда используется для приведения типов указателей. Не очень хорошая идея !!!!!)
  • reinterpret_cast <> Очень опасно. Используйте это, только если вы понимаете последствия.

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

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

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

0 голосов
/ 08 февраля 2009

(int*) - это синтаксис приведения типов из C. C ++ поддерживает его полностью, но это не рекомендуется.

В C ++ эквивалентное приведение должно было быть написано так:

int* canChange = static_cast<int*>(shouldnotChange);

И действительно, если бы вы написали это, компилятор НЕ позволил бы такое приведение.

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

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