2013-11-04 54 views
8

我有一個非靜態的常量方法,稱爲size_t A::m() 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() > 1(即方法本身的內容)具有相同的效果!

關於什麼可以用作斷點中的條件,Microsoft says that;

該條件可以是由 調試器識別的任何有效表達式。

於是我就和Expressions in the Debugger一看,和found this:副作用

一個常見原因是評估在 調試器窗口函數調用。這種評估通常是顯而易見的。更多的副作用的細微原因是對託管代碼中的屬性和其他 隱式函數調用的評估。

調試器無法判斷屬性評估或隱式函數調用是否有副作用。因此,默認情況下,調試器 不會自動評估隱式函數調用。屬性 默認情況下允許評估,但可以在選項 對話框中關閉。當函數調用或屬性尚未評估時,會出現一個 刷新圖標。您可以通過點擊刷新圖標 手動評估表達式。有關詳細信息,請參閱如何:刷新觀察值 值。

當關閉屬性或隱式函數調用的評估時,您可以使用ac格式修改器(僅適用於C# )強制執行評估。請參閱Format Specifiers in C#.

如果有人可以將上面的段落翻譯成英文,那將會很棒。我可以將函數放在這些調試器條件中嗎?

+0

'a'的類型是什麼? –

+0

@dauphic我已經添加了整個類和實例的定義 – arman

+0

'a'不是一個指針,並且不會重載操作符' - >'。 –

回答

8

這裏是我的,你所提供的幫助鏈接的翻譯:

  • 第1款:調用函數可能有副作用。評估屬性可能有副作用。第2段:調試器不能確定是否有副作用,所以我們假設:「函數=壞」,「屬性=好」(即「函數有副作用,屬性不會」 )。刷新與即時問題無關的圖標信息。
  • 第3段:想強制調試器?如果您使用的是C#,請在評估後輸入,ac

那麼,是什麼把它歸結爲是,如果你想打電話給你的評價功能和使用C#,把,ac

a->m() > 1,ac 

由於您使用C++,我想這歸結爲「您的評估報告中沒有適合您的功能!」出於調試目的,可能可以從A::m中刪除常量,因爲說明符不會(不應該)對邏輯流程有任何影響。但我甚至不確定這是否會奏效。

+1

感謝Scott,我認爲'ac'修飾符只適用於C#(它不適用於C++ - 'identifier 「ac」未定義)。也許這只是一個VC++的限制,然後...... – arman

+0

@ausairman當時,我沒有檢查你的標籤,並認爲你是在C#中。是的,你是對的,這是幫助文檔中更清晰的事情之一 - ',ac'只適用於C#。我將編輯我的帖子,但它看起來像是在手錶中「不要使用功能」。 –

+0

那麼如果是這種情況,那麼至少「這個表達式有副作用,不會被評估」的措辭構成了一個小錯誤(表達* *沒有副作用!),所以我會提交一份報告。 – arman

1

在這裏黑暗中拍攝,但您可能希望更深入地瞭解在方法聲明中使用const。您可能希望明確指出任何不會更改爲const的內容(IIRC正確const可以在方法聲明中的五個不同位置使用,所以請仔細觀察)。

const是編譯器強制實施的合同。如果你的方法訪問任何不是const的指針,這可能是一個問題。如果存在可能成爲問題的靜態變量。雖然你的編譯器可能會很滿意你的代碼中的const是好的,但IDE可能不像編譯器那麼聰明(因此可能需要更多的保證)。

沒有你的代碼,這很難說清楚,但這應該至少給你一個想法。

有關const一些更多的閱讀,此頁面似乎有一個像樣的教程:

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

+0

感謝您的回覆。我在代碼中添加了方法的內容,它是完全平凡的,除非'std :: vector :: size()'修改了某些東西,那麼它肯定沒有副作用! – arman

+0

如果你返回類似'(sizet)5'的東西而不是調用size()?會發生什麼? –

+0

同樣的效果 - '這個表達式有副作用,不會被評估。' – arman

8

評估任何函數調用都有副作用,因爲它會導致狀態發生變化,無論是在寄存器還是堆棧中,或者兩者兼而有之。這正是你引用的最後一段所說的。

在你的情況下,假設標準項目設置,寄存器和堆棧都被改變。 A 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()中斷到調試器在這個應用程序的任何一點,將顯示「此表達式有副作用,不會被評估。」

+1

我發佈的段落中的信息是傳達的信息嗎? – arman

+1

它措辭不佳。 「副作用的一個常見原因是在調試器窗口中評估函數調用。」這並不意味着調用函數通常是副作用的原因,而是說調用函數會產生副作用。 –

+0

我認爲你已經知道了 - 我看到的第一個理由是有道理的,並解釋了爲什麼即使const方法也不能在這裏使用。 – davidbak

1

翻譯語句有很好的答案,但這是一個很好的黑客可以使用。

在你的代碼中要添加斷點,添加一行如

auto debug = a.m() 

設置一個斷點,並且您可以在狀態

debug > 1 

添加,或者你可以做像這樣的東西

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

並且可以在調試行中設置斷點。