Это хорошее использование для "непостоянного" в C ++? - PullRequest
1 голос
/ 28 сентября 2011

У меня есть класс, который переносит дескриптор файла:

class FileHandle
{
    HANDLE hFile;
    TCHAR name[256];
public:
    LPCTSTR getName() const { /*(query system for name)*/ return this->name; }
};

Я придумал выбор дизайна:

Поскольку я буду часто запрашивать имя файла, чтобы минимизировать выделение кучи, которое могло бы произойти, если бы я возвратил std::wstring (я неоднократно видел, что это является узким местом в моих программах), вместо этого я решил оставить name поле внутри самого объекта и просто верните указатель на него, как показано.

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

Конечно, раздел, говорящий (query system for name), будет не работать, как показано, потому что name не mutable.

С одной стороны, абонент не ожидает изменения имени файла. Но с другой стороны, это не , что означает const в любом случае. Имя, безусловно, может измениться, просто вызывающая сторона не может его изменить. Так что, похоже, это не должно быть проблемой, но я не слишком уверен.

При каких обстоятельствах для меня будет хорошей идеей использовать mutable здесь? Почему?

Примечание 1: Windows гарантирует , что имена файлов имеют длину не более 256 символов , поэтому здесь нет проблемы переполнения буфера.

Примечание 2: Класс предназначен только для однопоточного использования. Меня не беспокоит одновременных модификаций, только модификации между заявлениями.


Почему const не подразумевает неизменность:

Это должно быть само за себя:

FileHandle file = ...;
const FileHandle &fileConst(file);
LPCTSTR name1 = fileConst.getName();
file.setName(_T("new name"));
LPCTSTR name2 = fileConst.getName();

Теперь name1 и name2 не равны. Так что не только может изменить имя файла довольно легко, но name1 сам также может измениться - даже если они оба const. Нет правила, гласящего, что const участники не могут измениться, просто они не могут быть изменены через const ссылку .

Ответы [ 3 ]

2 голосов
/ 28 сентября 2011

Недостающий метод здесь, на мой взгляд, это setName. Нет проблем с вашим кодом, потому что нет способа изменить name, и изменить его с помощью getName неудобно. Итак, если у вас есть немного

void setName(LPCTSTR newName) { _tcscpy(name, newName); /*or so*/ }

Вопрос теперь в том, как вы ожидаете, что он будет использоваться. Имеет смысл, что тот, кто должен менять имя, имеет доступ к неконстантному FileHandle. В таком случае нет проблем с использованием этого тривиального setName. Однако, если имя файла должно быть изменено на const FileHandle, у вас есть две проблемы: во-первых, это неудобно ... и во-вторых, вы не сможете вызвать setName выше. Чтобы позвонить, вам нужно изменить его на

void setName(LPCTSTR newName) const { _tcscpy(name, newName); /*or so*/ }

что на самом деле не имеет смысла, но давайте представим, что это так. Теперь, это не сработает, потому что FileHandle const также эффективно сделает name const. И это, наконец, подводит нас к mutable: изменение объявления name на:

mutable TCHAR name[256 + 1 /*for NULL terminator*/];

действительно позволит вам использовать setName для изменения имени const FileHandle. Для меня это выглядит как признак плохого дизайна, когда вы фактически взламываете свой собственный код. В этом отношении вы можете просто const_cast FileHandle и изменить его без использования mutable. Но я действительно не знаю специфики вашего дела, так что, может быть, это имеет смысл ...


Обновите, учитывая информацию, что getName на самом деле проверяет имя файла, и обновите name, если необходимо, прежде чем возвращать его: в этом случае, сделать name изменяемым действительно будет путь, потому что в противном случае это не может быть изменено в методе const. Как правило, получателю не рекомендуется изменять значение члена, значение которого он получает, но если ваш случай требует этого, тогда имеет смысл name a mutable.

0 голосов
/ 28 сентября 2011

Я бы сказал, что это приемлемо, но не идеально. Я думаю, что логически у вас есть имя, которое не зависит от дескриптора файла. Вы не спрашиваете имя дескриптора файла, вы спрашиваете имя файла, на который ссылается дескриптор файла. Получение этого имени не меняет дескриптор файла, поэтому логическое постоянство сохраняется. Что не является идеальным, так это то, что результаты могут измениться неожиданным образом:

LPCTSTR old_name = filehandle.getname();
changeFileName(filehandle);
LPCTSTR new_name = filehandle.getname();
// but old_name and new name still match!

Но это действительно не зависит от того, должен ли член быть изменяемым.

0 голосов
/ 28 сентября 2011

Конечно, имя файла может меняться со временем

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

Обновление:

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

Обновление 2:

В стандарте нет правила, предписывающего использованиеconst, никто не помешает вам пометить все ваши функции const и ваших участников volatile.Тем не менее, const обычно используется для указания того, что логическая константа объекта не изменится при вызове функции-члена;и volatile обычно используется, чтобы указать, что значение может быть изменено за пределами приложения.Вопрос о правильном использовании из mutable - который я считаю субъективным, и mutable не является посторонним для данного конкретного случая использования, особенно если функция также имеет модификатор volatile.Однако модификаторы const volatile встречаются редко, функции const возвращают различные значения после последующих вызовов, а значения, изменяемые вне вашего контроля, встречаются редко.Учитывая не только сигнатуру функции, но и количество предупреждений, которые должна включать документация, я думаю, что фактор неожиданности достаточно высок, чтобы его можно было считать неудачным вариантом использования, по крайней мере, в моей книге.

...