2012-11-12 24 views
3

一個框架,我需要使用的定義可以互斥所有者姓名存儲爲調試輔助一個簡單的互斥體類副本的時候我斷碼只是改變了一些算法使互斥鎖類型的模板參數,這樣我可以在這一個性能方面的原因通過,如果不需要鎖定:將返回,而不是常引用

class non_mutex 
{ 
public: 
    explicit non_mutex(const std::string& mutex_owner = "")  {} 

    bool acquire() const    {return true;} 
    bool release() const    {return true;} 

    std::string get_name() const {return "";} 
}; 

因爲這一個不保存名稱(有沒有必要調試這個),我改變了get_name()成員函數返回一個std::string,而不是const std::string&

現在我的問題是:難道這默默破壞任何東西?代碼編譯得很好,似乎也運行良好,但是在這個代碼庫中的測試很少,而且這個函數大多隻在錯誤發生時才使用,而不是常規。

這種更改會導致運行時失敗的情況是什麼?

注意,這是一個C++ 03的環境,但我很想在C++ 11分的答案了。

回答

4

通過值返回的那個可能會拋出一個壞的分配,參考之一是無拋出。所以這可能是一個問題。

此外,還有爲他們調用不同的重載和特點將不同的專業,但我不會擔心這一點的可能性。

+0

分配確實可能是一個問題,如果不太可能的話。鑑於我們在這裏還沒有右值引用,因此調用不同的重載有什麼潛力? (我正在擔心這些孩子的問題,這是一個24/7全天候運行的小設備。) – sbi

+0

你可能會很幸運:如果你的'std :: string'有一個小的字符串優化,那麼我認爲'std: :non_mutex :: get_name()'應該不在你的實現中。 –

1

那麼,你不再返回一個常數。你正在返回一個臨時的。

理論上這可能會讓用戶誤用返回值?也許?

Btw。我會這樣解決這個問題:

static std::string empty_string; 
const std::string& get_name() const { return empty_string; } 
+0

請注意,這具有不同的線程安全性要求,因爲多個互斥體將返回相同的名稱對象引用。 –

+0

@ JohannesSchaub-litb對於常量對象來說,這是否重要? –

+0

@Let_Me_Be:可能'empty_string'應該是一個常量對象,然後; -p。但我認爲你是對的,只要沒有人修改'empty_string'就不應該有任何特定的線程問題。 –

1

對於靜音破壞,一個區別是返回/返回對象的生命週期。例如,請考慮下面的代碼:

const string &stupid_user(const string &s) { return s; } 

const string &name = stupid_user(mtx.get_name()); 
mtx.acquire(); 
std::cout << name; 

現在,如果mtx的類型爲mutex那麼這個打印acquire後的互斥體的當前所有者的名稱。如果mtx有類型non_mutex然後它有未定義的行爲(const引用延長臨時的這種情況下的壽命)。未定義的行爲顯然允許它可能通過您的測試。

一個不太愚蠢的用戶:

const string &name = mtx.get_name(); 
mtx.acquire(); 
std::cout << name; 

現在用mutex的行爲是它打印的新主人,用non_mutex它打印的老東家。也許你的測試可以捕捉到它,也許它們不會,但是如果調用代碼假設了一個,而你提供了另一個類型的代碼,那麼你已經無聲地破壞了調用代碼。

或者怎麼樣:

auto &&name = mtx.get_name(); 
mtx.acquire(); 
std::cout << name; 

我覺得這個行爲等同於非愚蠢的用戶,但我不知道。

如果你(或者這個問題的未來訪問者)對嘈雜的破損感興趣,那麼它取決於你如何定義允許的表達式來使用你的Mutex概念(你希望你所呈現的兩個類都滿足)。

例如,如果表達式&mtx.get_name()被允許,則non_mutex不滿足該概念的要求。

如果您不允許使用該表達式,那麼non_mutex確實可以滿足要求 - 仔細查看允許涉及對get_name的調用的表達式。如果你所需要的只是它的返回值是「可兌換爲string」或其他的,那麼你很好。 (a)你犯了一個錯誤,那不是這樣做的,如果你沒有按照允許的表達式定義模板參數的要求,而是(a)你犯了一個錯誤,那不是(b)non_mutex不具有相同的成員函數簽名和返回類型。

+0

當我寫下「靜靜地」時,我的意思是說它不會導致任何編譯錯誤,因爲我並不擔心這些錯誤。當編譯失敗時,可以修復依賴返回值作爲引用的代碼。我擔心編譯的代碼,但可能會在運行時失敗。因此,這種「默默地」甚至可能涉及壯觀的錯誤。 (順便說一下,我沒有要求如何修復依賴於參考結果的代碼,我問你可能會得到什麼樣的代碼。「+ 1」是你給出的一個例子。 – sbi

+0

PS:As我已經(遲到了)寫了這個問題,那個平臺沒有C++ 11編譯器,所以我們不能從'auto'中獲益 – sbi

+0

也許我只是有一個精神錯亂,但不會同時存在兩個例子在你的答案的末尾)''non_mutex'失敗?我的意思是,獲得一個參考(將其「const」或「r值」下注)暫時不會延長臨時生命時間。所以這應該導致未定義的行爲不打印舊用戶。 –

0

我不認爲您的更改有任何問題。 get_name()都返回不可修改的左值;嘗試修改它們導致C++ 03中的編譯器錯誤。

如果您想要迂腐,您可以隨時根據SFINAE進行選擇,因爲您已對代碼進行了模板化。有了這個,你可以完全刪除non_mutex::get_name()

+0

'mutex :: get_name'不返回一個右值,它返回一個不可修改的左值。 –

+0

我知道如何修復暴露問題的代碼。我只是擔心我可能會錯過編譯時不會說出的代碼,但在運行時會失敗。 – sbi