有没有办法“这个表达有副作用,不会被评估。”?

时间:2017-10-31 17:58:11

标签: c++ visual-studio visual-studio-2017 natvis

在Visual Studio 2017中,我创建了一个调用C ++函数的.natvis调试器可视化规则。

在调试器中显示:

This expression has side effects and will not be evaluated.

除此之外,它还显示了一个蓝色箭头,可以点击它以强制它进行评估,然后它实际上会调用该函数。 (我认为这可能是最近的一个功能,因为我似乎记得在VS2013中尝试这个并且不记得它有旁路)

我的问题是:是否有某些方法可以永久地绕过此安全检查,以便它始终立即评估我的功能,并且不要求我点击箭头?

我看了一个非常相似的问题:"This expression causes side effects and will not be evaluated". How to suppress?其中接受的答案仅对C#有效(在C#表达式的末尾添加ac,强制调试器自动重新评估它)

我想如果存在这样的事情,它将成为以下机制之一:

  1. 一直禁用安全检查的注册表设置或其他全局设置。
  2. 一种注释代码或.natvis规则的方法,以便编译器知道它是一种安全且纯粹的无副作用函数
  3. 要提供有关应用程序的更多详细信息:我们在代码中使用uint32,它们是从字符串中散列出来的,并且我们有一个仅在开发版本中加载的字符串数据库。解码函数在二叉搜索树中查找u32 ID,返回在存储节点中找到的字符串。所以我知道它完全没有副作用且足够快,每次.natvis规则都这样说时,它不会影响调试体验。

2 个答案:

答案 0 :(得分:3)

经过进一步的研究,我怀疑没有办法告诉Visual Studio你的功能没有副作用,即使对于一个简单的无副作用的功能,如int MyTestFunction() { return 56; },它仍然会给"表达有副作用,不会被评估"观察窗口中的消息。

虽然这不是一个非常令人满意的答案,但我确实找到了解决这个问题的方法,即重新实现我试图调用的函数(在我的例子中通过表进行二进制搜索) .natvis CustomListItems标签的笨拙,丑陋的XML语法。

尽管这个标签的名称暗示它与列表有关,但似乎这个标签对于任何需要某种算法来实现的可视化器来说都是一种全能。在<CustomListItems>下面,您可以使用一堆不同的标签,这些标签可能足以实现任何算法:

  • <Variable>标记声明变量,
  • <Loop>标记用于迭代,
  • <Break Condition="myCondition">用于检查是否终止循环,
  • <Exec>标记用于执行表达式,改变<Variable>标记中声明的变量的值,
  • <If Condition="myCondition">用于分支
  • 您可以添加任意数量的<Item Name="name">value</Item>代码,每个代码都会在展开的变量下方的观察窗口中显示为一行。

据我所知,大多数这些算法标签只能在CustomListItems下使用(我只使用一些<Expand>标签尝试了常规<Variable>规则并得到错误表明它不支持)

必须重新实现已经在这种可怕语法中运行的C ++函数并不是很愉快(请记住,必须使用&gt;&lt;代替><,因为它是XML)。

然而,通过以下几点提示,它并不像它可能那么糟糕

  • 如果您在visual studio中编辑.natvis文件,保存文件会触发调试器重新评估显示而无需重新启动程序,因此迭代您的.natvis规则非常快。 (注意:从外部编辑器编辑.natvis文件时,这在VS2017中似乎不适用)
  • 在规则中使用大量<Item>个标签,基本上可以完成相同的&#34;打印调试&#34;。在尝试使用.natvis规则时,请使用<Item>打印出中间值。如果算法无法正常工作,这将使跟踪算法失败的位置变得更加容易。在工作时删除这些额外标签。

您可以在此处找到文档和CustomListItems的示例。

https://msdn.microsoft.com/en-us/library/jj620914.aspx

答案 1 :(得分:0)

我遇到了同样的问题,在搜索时遇到了这个话题。

我刚刚找到了一个解决方案,并想在这里发布:如果您在XML中将函数定义为“本征”,那么当您调用该内在函数时,编译器不会显示诸如This expression has side effects...之类的东西。

这是一个例子:

我写了一个自定义字符串类,它是这样的:

namespace rkstl
{
    namespace strings
    {
        //null-terminated string object consisting of 'char' elements
        class string 
        {
         public:    
             //... c'tors, copy c'tor and d'tor come here

             length(); //returns the length of null-terminated string: _mSize
             capacity(); //returns the length of the actual buffer: _mCap
             clear();

             //... other member functions

         private:
             char* _pStr; //the actual buffer
             size_t _mSize; //length of the string
             size_t _mCap; //length of the actual buffer
        };

        //null-terminated wide string object consisting of 'wchar_t' elements
        class wstring
        {
         //...
        };

    }
}

从我的实现中可以看到length()capacity()是内在函数。因此,如果我直接用.XML调用它们,那么编译器将显示This expression has side effects...,因此我将必须单击重新评估按钮(蓝色圆圈箭头)以查看数据是什么:

<Type Name="rkstl::strings::string">
<DisplayString>{_pStr,na}</DisplayString>
<StringView>_pStr,na</StringView>
<Expand>
  <Item Name="[string length]" ExcludeView="simple">length()</Item>
  <Item Name="[buffer capacity]" ExcludeView="simple">capacity()</Item>
  <ArrayItems>
    <Size>_pEnd - _pBegin</Size>
    <ValuePointer>_pStr</ValuePointer>
  </ArrayItems>
</Expand>

相反,我定义了内部函数来评估与类中相同的事物。而且我可以直接在.natvis XML中调用它们。这是我对rkstl::strings::string的.natvis实现:

<Type Name="rkstl::strings::string">
<Intrinsic Name="length_dbg" Expression="(_mSize)"/>
<Intrinsic Name="capacity_dbg" Expression="(_mCap)"/>
<DisplayString>{_pStr,na}</DisplayString>
<StringView>_pStr,na</StringView>
<Expand>
  <Item Name="[length of the string]" ExcludeView="simple">length_dbg()</Item>
  <Item Name="[capacity of the buffer]" ExcludeView="simple">capacity_dbg()</Item>
  <ArrayItems>
    <Size>_pEnd - _pBegin</Size>
    <ValuePointer>_pStr</ValuePointer>
  </ArrayItems>
</Expand>

您可以看到我已经将length_dbg()capacity_dbg()定义为本征。因此,调试器可以安全地调用它们并评估我想要显示的数据。结果如下:

enter image description here