【问题标题】:Can adding extra const qualifications break functionality (assuming compilation went fine)?添加额外的 const 资格可以破坏功能(假设编译正常)?
【发布时间】:2015-11-23 10:52:30
【问题描述】:

当我尝试对自己的代码应用 const-correctness 时,我经常必须在其他模块(由其他程序员编写)中的函数定义中添加 const 限定条件,以便在我自己的代码中使用这些函数。 (see here on back-patching const-correctness)

我一直认为,如果一切编译正常,这可能会导致功能损坏,因为const 标签只在编译时起作用。

然而,前几天我的一位同事坚持在我提交带有const 标签的代码之前,我应该重新运行所有自动化测试,我认为编译这样的代码就足够了。

他有意见吗?有没有办法应用 const 正确性可能会破坏现有功能?

编辑: 需要注意的是,通常我只需要对函数的指针参数执行此操作(例如 Something getSomething(Object* pObj)Something getSomething(const Object* pObj)。我不会更改返回类型或方法常量,因为这对于客户端代码来说不是问题。

【问题讨论】:

  • 到目前为止,您得到的所有答案似乎都在谈论将const 添加到变量。我将您的问题理解为将const 资格添加到成员函数. 您能否澄清一下您要添加的const 的类型?
  • 如果你有测试,你应该总是运行它们
  • 如果您没有测试,那么您应该始终创建它们。
  • 嗯,有没有什么工具可以扫码并指出你可以/应该在哪里添加const
  • 当然,我总是在提交自己的代码时运行测试。但是运行所有测试大约需要 3 个小时,这对于添加一些 const 标签来说似乎很多

标签: c++ testing compilation constants


【解决方案1】:

他们确实有道理。

  1. 如果您从最初为 const 的变量中丢弃 constness,则程序行为未定义。如果您添加 const 资格,则可能会将其引入代码中。

  2. 您可能无意中将函数重载切换为函数覆盖

  3. 定义了将匿名临时传递给采用const 引用的函数,但如果该函数采用非const 引用,则行为未定义。许多编译器允许非const(可能是偶然的,尽管有些人甚至称其为扩展)。从表面上看,您在解决此问题方面帮了每个人的忙,但您可能正在删除运行时依赖的未定义行为构造。

  4. C++ 标准坚持sizeof(T*) == sizeof(const T*)。在您进行非constconst 参数切换时,您的班级的v-table 布局可能会有所不同。当然,这不太可能,但您必须进行测试。

总之,您必须测试这些更改。

【讨论】:

  • 对于情况(3),这样的代码应该是格式错误的,而不是未定义的。 VC++ 坏了。 “许多编译器”中包含哪些编译器?
  • 我不同意您的回答,但澄清一下,(1) 是否暗示使用 const_cast 总是会产生未定义的行为?
  • 你在第 4 点是challenged
  • @Bathsheba "3.9.2.3. 指向布局兼容类型的 cv-qualified 和 cv-unqualified 版本 (3.9.3) 的指针应具有相同的值表示和对齐要求 (3.11)"跨度>
  • 因此,情况 (1) 仅适用于 const_cast 和等效项(OP 未提及)。看起来 (3) 是错误的, (4) 也是错误的,除非您的编译器不是 C++ 编译器。留下 (2) - 意外移除过载并用覆盖替换它。同样缺少的是在您constify 参数之后函数调度到不同覆盖的可能性;虽然这样的覆盖开关不应该改变功能,但有时现有的代码很糟糕。
【解决方案2】:

由于 const 方法可能与非 const 方法不同

class C
{
public:
    int& get() { return i; }    
    int get() const { return i; }
private:
    int i = 42;
};

你可能有不同的行为:

C c;

auto&& p1 = c.get();
auto&& p2 = c.get();
assert(&p1 == &p2); // true

const C c;

auto&& p1 = c.get();
auto&& p2 = c.get();
assert(&p1 == &p2); // not true.

【讨论】:

  • 感谢您提供具体示例
  • 嗯,就是truedoes not compile。 ;) 你可以让它工作,但不能使用原始的&& 不能直接应用于临时的int。您可以将c.get() 捕获到引用中,然后测试:const int& a = c.get(); const int& b = c.get(); assert(&a==&b);
  • @Yakk:想法就在那里 :) 无论如何都已修复。
【解决方案3】:

是的。
添加consts 的一个可能问题是稍后更改变量时可能出现未定义的行为(在编译器无法再阻止它的情况下)。
如果 f 在这里是 const 怎么办?

float f = 1.0;
//do something with f
readFromBinaryFile((char *)(&f), sizeof(f));
//do another something with f

//...

void readFromBinaryFile(char *c, size_t s)
{
    //... fill c
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 2019-01-22
    • 2013-04-07
    • 2021-04-11
    相关资源
    最近更新 更多