【问题标题】:Conditional breakpoint: This expression has side effects and will not be evaluated条件断点:这个表达式有副作用,不会被计算
【发布时间】:2013-11-15 17:37:23
【问题描述】:

我有一个名为 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() > 1' 为真时

这个表达式有副作用,不会被计算。

请注意,A::m() 不会修改任何内容,它仅调用向量的 .size() 方法并返回该值,因此表达式具有副作用的断言完全是错误的。其实替换断点条件为a.myvec.size() &gt; 1(即方法本身的内容)效果是一样的!

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

条件可以是任何被 调试器。

所以我去看看Expressions in the Debuggerfound this

副作用的一个常见原因是在 调试器窗口。这样的评价通常是引人注目的。一个更 副作用的微妙原因是对属性和其他的评估 托管代码中的隐式函数调用。

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

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

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

【问题讨论】:

  • a的类型是什么?
  • @dauphic 我已经添加了整个类和实例的定义
  • a 不是指针,也不会重载运算符 -&gt;
  • @dauphic 我修好了;虽然这只是一个例子,但这并不相关。
  • 我也遇到了同样的问题。一种解决方法是自己编写一个if,并在if 中设置断点。

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


【解决方案1】:

这是我对您提供的帮助链接的翻译:

  • 第 1 段:调用函数可能有副作用。评估属性可能会产生副作用。
  • 第 2 段:调试器无法判断是否有副作用,所以我们只是假设:“functions = bad”、“properties = good”(即“函数有副作用,properties 没有” )。刷新与当前问题无关的图标信息。
  • 第3段:要强制调试器?如果您使用的是 C#,请在评估后添加 ,ac

所以,归结为,如果您想在评估中调用一个函数并且使用 C#,请在其后面加上 ,ac

a->m() > 1,ac

由于您使用的是 C++,我认为这归结为“您的评估语句中没有函数!”出于调试的目的,您可能可以从A::m 中删除 const,因为说明符不会(不应该)对逻辑流程产生任何影响。不过,我什至不确定这是否可行。

【讨论】:

  • 感谢 Scott,我认为 ac 修饰符仅适用于 C#(它在 c++ 中不起作用 - identifier "ac" is undefined)。也许这只是 VC++ 的限制……
  • @ausairman Dang,我没有检查你的标签,还以为你在 C# 中。是的,你是对的,这是帮助文档中更明确的内容之一 - ,ac 仅适用于 C#。我会编辑我的帖子,但看起来这意味着您手表中的“不要使用功能”。
  • 好吧,如果是这样的话,那么至少This expression has side effects and will not be evaluated. 的措辞构成了一个小错误(表达式没有有副作用!)所以我会归档一份报告。
  • @ausairman 我怀疑微软愿意承认:This expression may have side effects. We don't really know. Just to be safe, it will not be evaluated. Upgrade to C# if you want better features.,但向他们报告问题永远不会有坏处。 (我几乎认为他们的语言是如此晦涩,只是为了帮助隐藏这一事实。:))
  • 如果函数是 const,那么这几乎可以保证它们没有副作用......
【解决方案2】:

评估任何函数调用都会产生副作用,因为它会导致状态发生变化,无论是在寄存器中还是在堆栈中,或两者兼而有之。这正是你引用的最后一段所说的。

在您的情况下,假设标准项目设置,寄存器和堆栈都已更改。使用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() 在此应用程序中的任何位置闯入调试器,它将显示“此表达式有副作用,不会被评估。”

【讨论】:

  • 我发布的段落中的哪里传达了这些信息?
  • 措辞不好。 One common cause of side effects is evaluating a function call in a debugger window. 这并不是说调用函数通常是产生副作用的原因,而是说调用函数会引起副作用。
  • 我想你已经明白了——我看到的第一个原因是有道理的,并解释了为什么这里不能使用 const 方法。
【解决方案3】:

翻译该语句有很好的答案,但这里有一个很好的技巧,有人可以使用。

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

auto debug = a.m()

在那里设置断点,你可以在条件中添加它

debug > 1

或者你可以这样做

if (a.m() > 1)
    bool debug = 1;

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

【讨论】:

    【解决方案4】:

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

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

    如果没有您的代码,很难确定,但这至少应该给您一个想法。

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

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

    【讨论】:

    • 感谢您的回复。我已经在代码中添加了方法的内容,这完全是微不足道的,除非std::vector::size() 修改了某些东西,否则它肯定没有副作用!
    • 如果你返回 (sizet)5 之类的东西并且从不调用 size() 会发生什么?
    • 同样的效果 - This expression has side effects and will not be evaluated.
    • 当时似乎是 VS 的问题。如果可以的话,我会提交一个错误。你不能得到比return 5; 更多的非副作用-y(假设你有一个 const 方法)。
    • 你可以做的最后一件事是让你的对象 const 并看看它是否也失败了......
    猜你喜欢
    • 2018-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-11
    • 2016-09-20
    • 1970-01-01
    相关资源
    最近更新 更多