这是一个C ++灾难,请查看此代码示例:
#include <iostream>
void func(const int* shouldnotChange)
{
int* canChange = (int*) shouldnotChange;
*canChange += 2;
return;
}
int main() {
int i = 5;
func(&i);
std::cout << i;
return 0;
}
输出为7!
那么,如果它能够改变一个假设为常数的参数,我们怎样才能确定C ++函数的行为??
编辑:我不是在问我如何确保我的代码按预期工作,而是我想知道如何相信别人的功能(例如某些dll库中的某些功能)不会改变参数或拥有某些行为......
答案 0 :(得分:21)
根据您的编辑,您的问题是“我怎么能相信第三方代码不是傻瓜?”
简短的回答是“你做不到”。如果您无权访问源代码,或者没有时间对其进行检查,那么您只能信任作者拥有书面的合理代码。在您的示例中,函数声明的作者明确声明代码不会使用const关键字更改指针的内容。您可以信任该声明,也可以不信任。正如其他人所建议的那样,有一些测试方法,但如果你需要测试大量的代码,那将是非常耗费人力的。也许比阅读代码还要多。
如果你是在一个团队工作,并且你有一个团队成员写这样的东西,那么你可以和他们谈谈它并解释它为什么不好。
答案 1 :(得分:12)
通过编写理智的代码。 如果您编写的代码是您无法信任的,那么显然您的代码将不值得信任。 几乎任何语言都可以使用类似的愚蠢技巧。在C#中,您可以通过反射在运行时修改代码。您可以检查和更改私有类成员。你如何防范这种情况?你没有,你只需要编写符合你期望的代码。
除此之外,编写一个单元测试,测试该函数不会改变其参数。
答案 2 :(得分:9)
C ++中的一般规则是该语言旨在保护您免受Murphy的攻击,而不是Machiavelli。换句话说,它意味着让维护程序员不会意外地更改标记为const的变量,而不是让某人不能更改它,这可以通过多种方式完成。
答案 3 :(得分:7)
C式演员表示所有投注均已关闭。这有点像告诉编译器“相信我,我知道这看起来很糟糕,但我需要这样做,所以不要告诉我我错了。”而且,你所做的实际上是未定义的。抛弃常量,然后修改值意味着编译器/运行时可以做任何事情,包括例如你的程序崩溃。
答案 4 :(得分:2)
不要在C ++中使用C样式转换 我们在C ++中有4个强制转换操作符(此处按危险顺序列出)
你总是可以告诉编译器你知道的比它更好,并且编译器会接受你的面值(原因是你不希望编译器在你真正知道更好的时候妨碍你)。 / p>
强大的编译器是一把双刃剑。如果你知道自己在做什么,这将是一个有用的强大工具,但如果你弄错了,它会在你的脸上爆炸。
不幸的是,编译器有大多数事情的原因,所以如果你超越它的默认行为,那么你最好知道你在做什么。演员是一件事。很多时候它很好。但是如果你开始抛弃const(ness),那么你最好知道你在做什么。
答案 5 :(得分:2)
我唯一可以建议的是从标记为只读的内存页面中分配变量shouldNotChange
。如果应用程序尝试写入该内存,这将强制OS / CPU引发错误。我并不是真的推荐这个作为验证函数的一般方法,就像你可能觉得有用的想法一样。
答案 6 :(得分:2)
执行此操作的最简单方法是不传递指针:
void func(int shouldnotChange);
现在将复制该参数。该函数可以随意更改所有值,但不会修改原始值。
如果您无法更改函数的界面,那么您可以在调用函数之前复制该值:
int i = 5;
int copy = i
func(©);
答案 7 :(得分:0)
(int*)
是来自C的转换语法.C ++完全支持它,但不推荐使用它。
在C ++中,等效演员应该是这样编写的:
int* canChange = static_cast<int*>(shouldnotChange);
事实上,如果你写的那样,编译器就不会允许这样的演员表。
你正在做的是编写C代码并期望C ++编译器能够捕捉到你的错误,如果你考虑它会有点不公平。