条件断点:此表达式具有副作用,不会被评估

时间:2013-11-04 23:01:08

标签: c++ debugging visual-studio-2013

我有一个名为size_t A::m() const的非静态const方法,如果它返回一个大于1的值,我想用它来触发断点。这里有class A和实例a

class A
{
public:
    std::vector<double> myvec;
    size_t m() const
    {
      return myvec.size();
    }
} a;

所以我在Visual Studio 2013中添加一个具有此条件的断点

a.m() > 1 // a is an instance of class A

但是,当我尝试编译它时,我从IDE获得以下消息:

  

无法设置以下断点:

     

在myFile.cpp,第xxx行,当'a.m()&gt; 1'是真的

     

此表达式具有副作用,不会被评估。

请注意A::m()不会修改任何内容,它只调用向量的.size()方法并返回该值,因此表达式具有副作用的断言完全是假的。事实上,a.myvec.size() > 1替换断点条件(即方法本身的内容)具有相同的效果!

关于什么可以用作断点中的条件,Microsoft says that;

  

条件可以是由其识别的任何有效表达式   调试器。

所以我去看看Expressions in the Debuggerfound this

  

副作用的一个常见原因是评估a中的函数调用   调试器窗口。这种评估通常是显而易见的。更多   副作用的微妙原因是对性质和其他的评价   托管代码中的隐式函数调用。

     

调试器无法判断属性是评估还是隐式   函数调用有副作用。因此,默认情况下,调试器   不会自动评估隐式函数调用。属性   默认情况下允许评估,但可以在选项中关闭   对话框。当尚未评估函数调用或属性时,a   出现刷新图标。您可以手动评估表达式   单击刷新图标。有关详细信息,请参见如何:刷新监视   值。

     

转换属性或隐式函数调用的评估时   off,您可以使用ac格式修饰符强制进行评估(对于C#   只要)。见Format Specifiers in C#.

如果有人可以将上段翻译成英文,那就太棒了。我可以将函数放入这些调试器条件中吗?

4 个答案:

答案 0 :(得分:8)

以下是您提供的帮助链接的翻译版本:

  • 第1段:调用函数可能有副作用。评估属性可能会产生副作用。
  • 第2段:调试器无法判断是否存在副作用,因此我们假设:“函数=坏”,“属性=好”(即“函数有副作用,属性不” )。刷新与即时问题无关的图标信息。
  • 第3段:想强制调试器?如果您使用的是C#,请在评估后添加,ac

所以,归结起来的是,如果你想在你的评估中调用一个函数并使用C#,那就把,ac放在它之后

a->m() > 1,ac

由于您使用的是C ++,我认为这可以归结为“评估报告中没有功能!”出于调试的目的,可能可以从A::m中删除const,因为说明符不会(不应该)对逻辑流有任何影响。我不确定这是否会奏效。

答案 1 :(得分:8)

评估任何函数调用都有副作用,因为它会在寄存器或堆栈中或两者中引起状态更改。这正是你引用的最后一段所说的。

在您的情况下,假设标准项目设置,寄存器和堆栈都会更改。 call指令用于调用m(),它将指令指针推送到堆栈,返回值存储在eax中。除了这两个明显的副作用之外,堆栈和寄存器也被为m的调用约定生成的序言/结尾修改。

这可以通过生成裸函数并使用内联汇编程序来验证,该汇编程序仅修改寄存器:

int __declspec(naked) foo()
{
    __asm
    {
        mov eax, 10
        jmp ebx
    }
}

int main()
{
    __asm
    {
        mov ebx, cnt
        jmp foo
    }
cnt:
    return 0;
}

如果您在监视列表中使用foo()在此应用程序中的任何位置进入调试器,它将显示“此表达式具有副作用且不会被评估。”

答案 2 :(得分:2)

翻译语句有很好的答案,但这是一个很好的黑客可以使用。

在要添加断点的代码中,添加一行,例如

debug > 1

在那里设置一个断点,你可以在条件

中添加它
if (a.m() > 1)
    bool debug = 1;

或者你可以做这样的事情

 .factory('AuthoringState', function() {
        var track = 0;
        var _pool = {};

        return  {
            addChange : function(data) {
                track++;
                var temp = _.cloneDeep(data);
                _pool[track] = temp;
                temp['track'] = track;
                return _pool[track];
            },
            undo : function(checklist) {
                    if(checklist['track'] === 1) {
                        return checklist;
                    }
                    return _pool[checklist['track'] - 1];
            },
            back : function(checklist) {
                    if(checklist['track'] === track) {
                        return checklist;
                    }
                    return _pool[checklist['track'] + 1];
            }
        }

})

并可以在调试行中设置断点。

答案 3 :(得分:1)

在黑暗中拍摄,但您可能希望更深入地查看方法声明中const的使用。您可能希望显式声明任何不能更改为const的内容(IIRC正确const可以在方法声明中的五个不同位置使用,因此请仔细查看)。

const是编译器强制执行的合同。如果您的方法访问任何非const的指针,则可能是一个问题。如果存在可能存在问题的静态变量。也有可能虽然你的编译器可能很高兴你的代码中的const很好,但IDE可能不像编译器那样聪明(因此可能需要更多的const保证)。

如果没有你的代码,那肯定很难说,但这至少应该给你一个想法。

有关const的更多阅读,此页面似乎有一个不错的教程:

http://www.cprogramming.com/tutorial/const_correctness.html