这是“可变”的好用途吗?在 C++ 中?
我有一个包装文件句柄的类:
class FileHandle
{
HANDLE hFile;
TCHAR name[256];
public:
LPCTSTR getName() const { /*(query system for name)*/ return this->name; }
};
我提出了一个设计选择:
因为我将经常查询文件名,以便最大限度地减少如果我返回 std::wstringstd::wstring 时会发生的堆分配code> (我多次发现这是我的程序中的瓶颈),我决定在对象本身内部保留一个 name
字段,并只返回一个指针如图所示。
当然,文件的名称可能会随着时间的推移而改变,所以我无法避免每次都查询它。我只能避免重新分配。
当然,(名称查询系统)
部分将无法如图所示工作,因为 name
不是可变的
。
一方面,调用者不希望文件名发生更改。但另一方面,无论如何,这不是 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
引用更改它们。
I have a class that wraps a file handle:
class FileHandle
{
HANDLE hFile;
TCHAR name[256];
public:
LPCTSTR getName() const { /*(query system for name)*/ return this->name; }
};
I have come up with a design choice:
Since I will be querying the file name often, in order to minimize heap allocations which would happen if I returned std::wstring
(I have repeatedly seen that this is a bottleneck in my programs), I have instead decided to keep a name
field inside the object itself, and just return a pointer to it as shown.
Of course, the name of the file can change over time, so I can't avoid querying it every time. I can only avoid the reallocation.
Of course, the section saying (query system for name)
would not work as shown because name
isn't mutable
.
On the one hand, the caller doesn't expect the file name to change. But on the other hand, that's not what const
means, anyway. The name can certainly change, it's just that the caller can't modify it. So it doesn't look like it should be a problem, but I'm not too sure.
Under what circumstances would it be a good idea for me to use mutable
here? Why?
Note 1: Windows guarantees that file names are at most 256 characters long, so there's no buffer overflow issue to consider here.
Note 2: The class is only designed for single-threaded use. I'm not worried about concurrent modifications, only modifications in between statements.
Why const
doesn't imply immutability:
This should be self-explanatory:
FileHandle file = ...;
const FileHandle &fileConst(file);
LPCTSTR name1 = fileConst.getName();
file.setName(_T("new name"));
LPCTSTR name2 = fileConst.getName();
Now name1
and name2
aren't equal. So not only can the file name change quite easily, but name1
itself can also change -- even though they're both const
. There's no rule saying that const
members can't change, just that they can't be changed through the const
reference.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
据我所知,这里缺少的方法是
setName
。您的代码本身没有问题,因为无法更改name
,并且通过getName
更改它很尴尬。因此,假设您现在有一些问题是您希望如何使用它。这是有道理的,无论谁应该更改名称,都可以访问非常量的
FileHandle
。在这种情况下,使用这个简单的setName
没有问题。但是,如果应该在const FileHandle
上更改文件名,则会遇到两个问题:首先,这很尴尬……其次,您将无法调用setName上面。为了能够调用它,您必须将其更改为
这也没有真正意义,但让我们假设它确实有意义。现在,这不起作用,因为
FileHandle
为 const 也会有效地使name
也为 const。这最终给我们带来了mutable
:将name
的声明更改为:确实允许您使用
setName
来更改name
的名称代码>常量文件句柄。对我来说,这看起来像是糟糕设计的标志,实际上是在破解自己的代码。就此而言,您只需const_cast
FileHandle
即可,并在不使用mutable
的情况下更改它。但我真的不知道你的情况的具体情况,所以也许它确实有意义......更新,考虑到
getName
实际检查文件名并更新name 的信息
如果在返回之前需要的话:在这种情况下,使name
可变确实是一种可行的方法,因为否则它不能在 const 方法中更改。通常不建议 getter 更改其所获取值的成员的值,但如果您的情况需要这样做,那么将name
设为mutable
是有意义的。The missing method here, as I see it, is
setName
. There's no problem with your code as it is, because there's no way to changename
, and changing it viagetName
is awkward. So, assuming you'd have someQuestion now is how you'd expect it to be used. It makes sense that whoever is supposed to be changing the name, has access to a non-const
FileHandle
. In such case, there's no problem using this trivialsetName
. If, however, the file name should be changed on aconst FileHandle
, you have two problems: first, it's awkward... and second, you won't be able to call thesetName
above. To be able to call it, you'd have to change it towhich doesn't really makes sense either, but let's pretend it does. Now, this won't work, because
FileHandle
being const would effectively makename
const as well. And this finally brings us tomutable
: changingname
's declaration to:will indeed allow you to use
setName
to change the name of aconst FileHandle
. To me, this looks like a sign of a bad design, where you're actually hacking your own code. For that matter, you can justconst_cast
theFileHandle
, and change it without usingmutable
. But I really don't know the specifics of your case, so maybe it does make sense...Update, given the information that
getName
actually checks the name of the file, and updatesname
if needed before returning it: in that case, makingname
mutable would indeed be the way to go, because otherwise it can't be changed from within a const method. It is generally not advised for a getter to change the value of the member whose value it's getting, but if your case dictates that, then makingname
amutable
would make sense.我想说这是可以接受的,但并不理想。我认为逻辑上你有一个独立于文件句柄的名称。您不是在询问文件句柄的名称,而是在询问文件句柄所引用的文件的名称。获取该名称不会更改文件句柄,因此保留了逻辑常量。不理想的是结果可能会以意想不到的方式发生变化:
但这实际上与成员是否应该可变无关。
I would say it is acceptable, but not ideal. I think logically you have a name that is independent the file handle. You are not asking for the name of the file handle, you are asking for the name of the file that the file handle is referring to. Getting that name doesn't change the file handle, so the logical constness is preserved. What is not ideal is that the results could change in unexpected ways:
But that is really independent of whether or not the member should be made mutable.
您确定吗?当文件句柄处于打开状态时,可以更改文件名吗?如果是这样的话,那么这不是
mutable
的好用。当无法实现按位常量时,mutable
可以实现逻辑常量,就像缓存数据的情况一样。但是,如果两个连续的const
调用返回不同的值,getName()
函数的调用者将会感到惊讶。更新:
如果预计属性会从程序声明外部更改,则应通过声明函数
const volatile
来做出该声明,然后使用可变
可能是合理的。但请注意,这种方法还有另一个问题,即函数的调用者保留指向文件名的指针,并且对该函数的后续调用将更改其内容。这意味着该函数的结果也应被视为易失性
。更新 2:
标准中没有规定 const 的使用规则,没有人会阻止您标记所有函数
const
和您的成员不稳定
。然而,const
通常用于表示对象的逻辑常量不会因调用成员函数而改变;和易失性
通常用于指示该值可以从应用程序外部更改。问题是关于mutable
的良好使用 - 我认为这是主观的 - 并且mutable
并不是这个特定用例的局外人,特别是如果函数也有一个 volatile 修饰符。但是,const volatile
修饰符很少见,const
函数在后续调用后返回不同值的情况很少见,并且在您控制之外更改值的情况也很少见。不仅考虑到函数签名,还考虑到文档应包含的警告数量,我认为令人惊讶的因素足够高,至少在我的书中,这被认为是一个糟糕的用例。Are you sure about that? Can a file name be changed while there is an open handle to it? If that's the case, then this is not a good use of
mutable
.mutable
is there to achieve logical constness when bitwise constness cannot be achieved, like is the case with cached data. However, callers of yourgetName()
function would be surprissed if two consecutiveconst
calls would return different values.Update:
If the property is expected to change from outside the program declaration, then you should make that statement by declaring the function
const volatile
, and then the use ofmutable
may be justified. However note there is another problem with this approach, in that a caller of the function keeps the pointer to the file name around and a subsequent call to the function will change its contents. That means that the result of this function should be consideredvolatile
as well.Update 2:
There is no rule in the standard that dictates the uses of
const
, no one will stop you from flagging all your functionsconst
and your membersvolatile
. However,const
is usually used to indicate that the logical constness of the object won't change by invoking a member function; andvolatile
is usually used to indicate that the value may be changed from outside the application. The question is about good use ofmutable
-which I consider subjective-, andmutable
is not an outsider to this particular use case specially if the function has avolatile
modifier as well. However,const volatile
modifiers are rare,const
functions returning different values after subsequent calls are rare, and values being changed outside your control are rare. Considering not only the function signature but the ammount of warnings that the documentation should include, I think that the surprise factor is high enough for this to be considered a bad use case at least in my book.