我正在尝试在我的项目中实现C ++库的使用,该库未在其访问函数上使用const修饰符。到目前为止,我一直在我的所有代码中使用const,但这个新库导致了两个主要问题:
如果这些参数是由库定义的类型,则作为const引用传递参数的函数不能使用参数的访问函数。
具有库定义的类型的成员对象的类不能在const函数中使用这些对象的访问函数。
解决此问题的最佳方法是什么?最简单的解决方案是简单地从我的代码中删除所有const的使用,但这样做会非常令人沮丧。
其他信息:在这种情况下,我可以访问源代码,并且可以看到访问功能不会修改任何内容。我省略了这些信息,因为我对更一般的情况感兴趣。对于我的方案,const_cast
似乎是要走的路
PS图书馆作家不是邪恶的!这是一个粗略和准备好的代码,他善于开源。我可以放弃图书馆并使用其他人注意到的更专业的东西。但是,对于这个时间有限的小项目,该库接口的简单性使其成为最佳选择。
答案 0 :(得分:5)
判断库中的函数是否实际修改了它是否容易?
如果它很容易分辨,那么你可以const_cast
你的const指针/对非const的引用并调用库函数。您可能希望在库类周围添加一个包装器来为您执行此操作,这是繁琐且冗长的,但是从您的类中获取该代码。这个包装器可能是一个子类,它添加了一些const访问器,这取决于你使用库类的方式是否允许它工作。
如果很难说,或者他们确实修改了东西,那么你需要在代码中使用非const实例和对库类的引用。 mutable
可以帮助类型(2)的那些,但对于类型(1)的那些,你只需要传递非const参数。
有关为什么它可能很难的一个例子,请考虑库作者可能写了这样的东西:
struct Foo {
size_t times_accessed;
int value;
int get() {
++times_accessed;
return value;
}
};
现在,如果您const_cast
const
实例Foo
并致电get()
,则您有未定义的行为[*]。所以你 以确保get
确实不会修改它所调用的对象。您可以通过确保永远不会创建Foo
的任何const实例来缓解这一点,即使您确实对非const实例进行了const引用。这样,当您const_cast
并致电get
时,您至少不会导致UB。它可能会使您的代码混乱,字段会不断更改您的函数声称不会修改的对象。
[*]为什么它是未定义的行为?它必须是,语言可以保证const
对象的值永远不会在有效程序中更改。这种保证允许编译器做有用的事情。例如,它可以将static const
个对象放在只读数据部分中,并且可以使用已知值优化代码。它还意味着具有可见初始化程序的const
整数对象是编译时常量,标准使用它来将其用作数组大小或模板参数。如果修改const对象不是UB,那么const对象将不会是常量,并且这些事情是不可能的:
#include <iostream>
struct Foo {
int a;
Foo(int a) : a(a) {}
};
void nobody_knows_what_this_does1(const int *p); // defined in another TU
void nobody_knows_what_this_does2(const int *p); // defined in another TU
int main() {
const Foo f(1);
Foo g(1);
nobody_knows_what_this_does1(&f.a);
nobody_knows_what_this_does2(&g.a);
int x;
if (std::cin >> x) {
std::cout << (x / f.a); // Optimization opportunity!
std::cout << (x / g.a); // Cannot optimize!
}
}
因为f
是一个const对象,因此f.a
是一个const对象,所以优化器知道f.a
在函数末尾使用时值为1。如果它选择的话,它可以优化分裂。它不知道关于g.a
的相同内容:g
不是const对象,指向它的指针已被传递给未知代码,因此其值可能已更改。因此,如果您是nobody_knows_what_this_does1
或nobody_knows_what_this_does2
的作者,并且您正在考虑const_cast
p
并使用它来修改其参赛作品,那么您只能这样做如果你以某种方式知道referand是非const的话。通常你不这样做,所以通常你不使用const_cast
。
答案 1 :(得分:2)
我认为您有以下选择:
如果您确定库正在使用const
说明符,那么您可以使用const_cast<>
来删除对象的常量。文库
或者,您可以制作const对象的非常量副本并将其传递给库,然后将更改更新为原始对象上的非常量部分
搜索另一个const-correct
从代码中删除所有const(不推荐)
答案 2 :(得分:2)
另一个选择是将对象复制到可修改的温度并将其调整。如果您在班级提供复制构造函数并且不太昂贵的情况下,这可能是最安全的做法。这是我可用的首选方法,因为我知道它是100%安全的。愚蠢的例子:
int getInfoFromString(String& str); //what?? why isn't str const :(
所以我做了
String temp(str);
int stuffINeed = getInfoFromString(temp);
//happy
答案 3 :(得分:1)
另一个建议:您是否熟悉mutable
关键字?如果你正确使用它,它实际上可能完全实现了你正在尝试做的事情,只需在你的代码中添加一个单词。这个关键字可以在goto
的层面上唤起宗教观点,因为它可能被用作每100次使用的kludge,因为它确实是最好的设计选项。在你的情况下,它是有争议的,但它我认为它符合精神:你讨厌的库对象是可以伪造修改而不破坏你的方法的语义常量的东西,所以继续
class Outer {
mutable Inner inner;
public void foo() const {
inner.nonConstMethod(); //compiles because inner is mutable
}
};
答案 4 :(得分:1)
如果库的接口不大,您可以创建一个包装器,通过转换或复制参数将代码调整为预期类型,这些参数将传递给库的函数。
但是,为了使用该库,请不要降低代码质量。