【问题标题】:Modifying constant object修改常量对象
【发布时间】:2013-07-24 12:06:04
【问题描述】:

我正在通过面试问题寻找初级 C++ 开发人员职位。问题是(引用):

以下代码正确吗?

struct Foo
{
    int i;
    void foo ( void ) const
    {
        Foo* pointer = const_cast<Foo*>(this);
        pointer->i = 0;
    }
};

我会回答:

代码本身根据 C++03 和 c++11 标准是有效的,并且会成功编译。 但它可能会在赋值 pointer->i 期间调用未定义的行为 = 0; 如果调用 foo() 的类的实例被声明为 const

我的意思是以下代码将成功编译并导致未定义的行为。

struct Foo
{
    int i;
    Foo ( void )
    {

    }
    void foo ( void ) const
    {
        Foo* pointer = const_cast<Foo*>(this);
        pointer->i = 0;
    }
};

int main ( void )
{
    Foo foo1;
    foo1.foo();   // Ok

    const Foo foo2;
    foo2.foo();   // UB

    return 0;
}

我的答案是正确的还是我遗漏了什么?谢谢。

【问题讨论】:

  • 是的,没错。
  • “正确”是一个相当模糊的词。它是格式良好的,这意味着它没有可诊断的错误,但(如您所说)可能会导致未定义的行为。
  • 来自设计 POV 的 IMO 它不是“正确的”,因为 const Foo foo; foo.foo(); 不应该是 UB。使用mutable 成员会更好。
  • @MatsPetersson 我同意,这些是相关问题。我只是想确保我做的一切都是正确的。我应该删除问题吗?
  • 鉴于您通过了第一个问题,接下来的问题是:举一个例子,说明 const_cast 何时使用既安全又实用,这不是一个玩具示例。

标签: c++ c++11 constants undefined-behavior


【解决方案1】:

我首先要问他们对“正确”的模棱两可的定义是什么意思。您需要了解程序的规范及其预期行为

正如您所说,如果他们只是询问它是否编译,那么答案是“是”。但是,如果他们确定正确以确保安全,那么您可以讨论您在问题中陈述的事实。

通过这种方式回答,面试者可以看到你是如何分析你被问到的,而不是直接回答,在我看来这是一件好事。

【讨论】:

    【解决方案2】:

    这段代码在法律上可能是正确的,但我想,这个问题的目的是确定你是否理解 const 本身的概念。因为,在语义层面上,您有一个函数采用隐式 const 对象指针,然后它会对其进行修改,这几乎可以肯定是一个错误。

    在某些情况下,这可能是需要的(因为修改是一些返回值的缓存,或者不会改变对象语义值的类似操作),您可以使用 mutable 关键字作为变量问题。

    【讨论】:

    • 谢谢。在答案中提到这一点是个好主意,将i 声明为mutable 将修复提到的可能的UB。
    • 移除 constness 是设计错误的标志。然后,您开始分析这样做的后果。
    【解决方案3】:

    作弊编译器将承担后果。

    struct Foo
    {
        int i;
    
        Foo(int a):i(a){}
    
        void foo ( void ) const
        {
            Foo* pointer = const_cast<Foo*>(this);
            pointer->i = 0;
        }
    
        bool operator<(const Foo& rhs) const{
            return i<rhs.i;
        }
    };
    
    #include <map>
    
    int main ( void )
    {
        std::map<Foo,int> kk;
    
        for(int i=0;i<10;++i){
            kk.insert(std::make_pair(Foo(i),i));
        }
    
        std::map<Foo,int>::iterator ite = kk.find(Foo(4));
        const Foo& foo4 = ite->first;
        foo4.foo();
    
        ite = kk.find(Foo(4));
        const Foo& tmp = ite->first; // crack
    
        return 0;
    }
    

    程序将在“const Foo& tmp = ite->first;”处破解

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-09-22
      • 1970-01-01
      • 2015-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-22
      • 1970-01-01
      相关资源
      最近更新 更多