在 C++ 中,将 aconst void *
用于函数的参数类型是否有任何价值void *
?由于 avoid *
是不透明的,除了用户这样做之外,是否存在任何修改风险reinterpret_cast
,在这种情况下,他们也可以const_cast
在 a 上做同样的事情const void *
,因此人们真的会买任何东西吗?我问是因为我使用了一个用于共享指针的实用程序模板类,它提供了一个专门化void
以避免void &
问题,但没有提供专门化const void
,因此我想知道这只是一个疏忽还是永远不需要它?
6 回答
它提供了与其他指针类型相同的好处:除非您明确放弃 -ness const
,否则您无法修改指向的内容。const
在接口中,const void*
是客户端代码的标志,表明您传入的任何内容都可以读取但不能写入。例如,std::memcpy
声明为
void *memcpy(void *dest, const void *src, std::size_t count);
这表明它将读取src
和写入dest
. 当然,如果它真的是用 C++ 实现的(可能但不太可能),它必须将两个指针都转换为其他类型。
如果你觉得这个“没有给你买任何东西”,那么显然是const
关键字本身没有任何价值。
memcpy
接受两个指针参数,一个void*
和另一个const void*
。第二个参数可以从const char*
(或其他指向常量对象类型的指针)参数隐式转换,而第一个参数不能。
没有隐式转换就是价值——它迫使用户在他们想要的(不太可能的)事件中故意丢弃 const,而不是意外丢弃它。
然后在 的实现memcpy
或类似函数中,程序员必须在尝试修改其引用之前const_cast
对参数进行或 C 风格的转换。const void*
他们将能够对static_cast
非常量参数并修改其引用。你需要写的那种演员希望能告诉你一些关于你正在做的事情是否明智的事情。
我认为,如果您的 shared_ptr 辅助函数需要void
特别对待,那么他们将需要特别对待所有 cv 限定void
。所以这是四种情况:void
, const void
, volatile void
, const volatile void
。但是,如果这些功能的用户过去曾在 a 上尝试过shared_ptr<void>
,并抱怨它不起作用,但从未在 a 上尝试过shared_ptr<const void>
,则可能没有出现问题。
也许shared_ptr<void>
已经足够不寻常了,以至于它还没有出现。也许使用 a 的人shared_ptr<void>
往往不介意抛弃 cv-qualifiers,因为每当有人最终恢复正确的类型时,他们也会恢复正确的限定符。
想一想 - 确实shared_ptr<const void>
有效,或者shared_ptr
调用删除器的代码是否需要从T*
to隐式转换void*
?我不记得我是否曾经使用过shared_ptr<const T>
.
不要忘记const
. 即使有人总是可以将它扔掉,但它的const
作用是表明不应通过指针更改所指向的事物的原始意图。 const_cast
(reinterpret_cast
就此而言)应始终谨慎使用,并应在必要时让程序员暂停。
嗯,是的,有(一些)相同的优点const
总是有:它记录了内容不应该被改变的事实。
想象一下下面的代码:
int const object = some_value();
some_function(&object);
此调用仅在函数参数声明为 时编译void const*
,否则客户端将需要 aconst_cast
来抛弃 constness。当然,我们既不希望客户有这种不便,也不希望他们对他们的数据撒谎(通过抛弃 constness)。
“自我记录”代码仍然有好处。
store_pod(const void* data, std::size_t bytes);
没有任何注释可以让您看到指向的数据不会被修改。
另外,请注意,要打破这个const
承诺,函数需要同时执行 aconst_cast
和 a reinterpret_cast
。
与它的所有用途一样,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
}