在C ++中,使用const void *
作为void *
上的函数的参数类型是否有任何价值?由于void *
是不透明的,除了用户执行reinterpret_cast
之外,是否存在任何修改风险,在这种情况下,他们同样可以在const_cast
上执行const void *
,因此一个真的买什么?我问,因为我正在使用实用程序模板类来提供共享指针,它在void
上提供了专门化以避免void &
问题,但没有为const void
提供专业化,因此我想知道这是否只是是疏忽还是永远不需要?
答案 0 :(得分:9)
它提供了const
对其他指针类型提供的相同好处:除非明确抛弃const
,否则无法修改指向的内容。在接口中,const void*
是客户端代码的标志,无论您传入的是什么,都可以读取但不能写入。例如,std::memcpy
被声明为
void *memcpy(void *dest, const void *src, std::size_t count);
表示它将读取src
并写入dest
。当然,如果它真的是用C ++实现的(可能但不太可能),它必须将两个指针都转换为其他类型。
如果您认为这“不会给您带来任何好处”,那么const
关键字本身显然没有任何价值。
答案 1 :(得分:4)
memcpy
有两个指针参数,一个void*
,另一个const void*
。第二个参数可以从const char*
(或其他指针到const-object-type)参数隐式转换,而第一个参数则不能。
缺少隐式转换是值 - 它会强制用户故意在他们想要的(不太可能的)事件中抛弃const,而不是意外丢弃它。
然后在memcpy
或类似函数的实现中,程序员在尝试修改其引用之前必须const_cast
或C样式转换const void*
参数。他们将能够static_cast
非const参数并修改其参考。你需要编写希望的演员表,告诉你一些关于你所做的事情是否明智的事。
我认为如果你的shared_ptr助手函数需要专门处理void
,那么他们需要专门处理所有符合cv标准的void
。这就是四种情况:void
,const void
,volatile void
,const volatile void
。但是,如果这些函数的用户过去曾在shared_ptr<void>
上尝试过,并且抱怨它不起作用,但从未在shared_ptr<const void>
上尝试过,那么问题可能还没有出现
也许shared_ptr<void>
已经不足以让它没有出现。也许那种使用shared_ptr<void>
的人往往不介意丢弃cv-qualifiers,因为每当有人最终恢复正确的类型时,他们也会恢复正确的限定符。
来想一想 - shared_ptr<const void>
是否正常工作,或调用删除者的shared_ptr
中的代码是否需要从T*
隐式转换为void*
?我不记得我是否使用过shared_ptr<const T>
。
答案 2 :(得分:3)
不要忘记const
的“文档价值”。即使有人总是可以抛弃它,const
也可以表示不应该通过指针改变指向的东西的原始意图。 const_cast
(以及此问题reinterpret_cast
)应始终谨慎使用,如果需要,应立即让程序员暂停。
答案 3 :(得分:2)
是的,const
总是有(某些)相同的优点:文件内容不应该被改变的事实。
想象一下以下代码:
int const object = some_value();
some_function(&object);
如果函数参数声明为void const*
,则此调用仅编译,否则客户端需要const_cast
来抛弃constness。当然,我们既不希望客户有这种不便,也不希望他们对他们的数据撒谎(通过抛弃常量)。
答案 4 :(得分:1)
“自我记录”代码仍然有好处。
store_pod(const void* data, std::size_t bytes);
没有任何注释可以让您看到指向的数据不会被修改。
另请注意,要打破const
承诺,函数需要同时执行const_cast
和reinterpret_cast
。
答案 5 :(得分:1)
与const
的所有用途一样,它有两个目的。关于函数的实现,它将帮助编译器检测错误,正如你所提到的,可以通过const_cast
(或C风格的强制转换)强制和沉默。
但是const
是第二个目的,它提供了不会修改对象的承诺,这样做可以让用户将指针传递给const对象(假设你会信守诺言),有效能够更广泛地使用您的功能。这可以通过这个简单的例子看出:
void foo( const void* );
void bar( void* );
int main() {
const int value = 10;
foo( &value ); // correct, the function promises not to modify the value
//bar( &value ); // error, this would break const correctness
}