【发布时间】:2014-11-21 17:23:35
【问题描述】:
如果您尝试传递对临时对象的引用,则需要const:
这意味着在 C++ 中不可能将对象的可修改包装器建模为临时对象(无需强制使对象成为左值):
inline char * PcToUnix(AutoCStringBufferA & buffer) { return PcToUnix(buffer, buffer.size()); }
inline char * PcToUnix(CStringA & str) { return PcToUnix(make_autobuffer(str)); }
PcToUnix :将字符缓冲区从 CR+LF 原位转换为 CR。
make_autobuffer :接受 CString,并锁定其底层字符缓冲区,以便我们可以在 autobuffer 的生命周期内直接访问以对其进行操作。
所以我不能编写一个调用语句,它采用底层字符串,将其包装在缓冲区管理对象(可变)中,将其传递给操作缓冲区内容的函数并返回,除非 autobuffer 是声明为const &:
错误:
inline char * PcToUnix(AutoCStringBufferA & buffer) { return PcToUnix(buffer, buffer.size()); }
好吗?!
inline char * PcToUnix(const AutoCStringBufferA & buffer) { return PcToUnix(buffer, buffer.size()); }
但“正确”的形式似乎指定了以下合同:“我不会修改您的缓冲区”。这里的 constness 在 autobuffer 对象的级别上是逻辑上正确的 - 它在 PcToUnix() 期间没有被修改 - 缓冲区包装器对象本身(即 autobuffer)在 PcToUnix 期间没有被修改 - 所以它是确实是const...
但是,但是,它正在修改其底层对象 - 根据定义 - 其他东西的包装器 - 并且其他东西被修改了。
在我看来,这似乎是 C++ const 的一个根本缺陷。没有办法同时满足当前规则(不使用非标准编译器行为或编写误导性 API 合同或编写不必要的冗长代码。
详细方法:
inline char * PcToUnix(CStringA & str) { auto adapter = make_autobuffer(str); return PcToUnix(adapter); }
误导性的 API 方法:
inline char * PcToUnix(const AutoCStringBufferA & buffer) { return PcToUnix(buffer, buffer.size()); }
inline char * PcToUnix(CStringA & str) { return PcToUnix(make_autobuffer(str)); }
如果 C++ 提供了一种方法来指定包装器的 constness 与被包装对象的 constness 分开,那么我们就有了一种健全的方法来创建规则并简洁地表达 API。但我只是不知道如何做到这一点。
预智能指针(或对于所有没有包装层的上下文)可以单独指定指针的常量与底层对象的常量:
T * const pConstPointerToMutableObject;
const T * pMutablePointerToConstObject;
const T * const pConstPointerToConstObject;
但是对于包装对象没有任何相应的支持。没有办法将referer的constness与referee的constness分开来表达。也没有任何一套合理的规则来定义或控制const 的交换/关联/分配性质。
我不明白为什么没有经常提出这个问题。我经常偶然发现这一点,并发现const 是一个巨大的 PIA,因为它。
理想情况下,代码应该是可堆肥的——即,应该能够将一些更简单的对象包装在另一层以某种方式适应它——也许过滤访问,或添加有关管理子对象的智能,或延迟底层事物的实例化,等等,这样就可以建立一个数据的复杂和特定的接口,而不必一遍又一遍地重新设计基本对象——只需包裹在一层或两层中,为上下文添加必要的智能/逻辑/接口/适应这是需要的。
但由于 const 正确性问题,C++ 几乎不可能做到这一点。 (或者,我太愚蠢了,无法弄清楚如何做这一切,在我广泛的阅读中,我已经设法错过了如何做,甚至没有人在讨论这些问题而只是掩饰并忽略const 的这一方面)。也许这里的某人可以免除我的任何错误??
【问题讨论】:
-
“但是没有任何对包装器对象的相应支持。”
unique_ptr<const T> -
"
const如果您尝试传递对临时对象的引用,则需要。" 首先解释您为什么要这样做。并考虑右值引用。 -
临时销毁后使用
PcToUnix的返回值会怎样? -
PcToUnix是一个 void 函数 - 它只会在处理它的 char 缓冲区中产生副作用。我意识到这个规则的存在是为了避免你试图修改一个临时的,然后在任何人看到副作用之前将其销毁。但是,对于包装器/适配器类型,副作用是在底层对象中,而不是在临时包装器中 - 因此处理它是完全合法的,并且没有任何损失。 -
unique_ptr<const T>只是一个带有 API 的包装器对象的反例,它允许您指定裁判的常量。
标签: c++ wrapper const-correctness