這很奇怪。C++ 11類型轉換heisenbug(XCode 6.1,clang)
OSX 10.10 LLVM 6.0 的XCode 6.1
test_assert("Wierd", String{"ABC"}, "ABC"); // claims not equal
字符串是我的自定義類(包裝一個Python字符串原語),並應通過這個測試。
這裏的test_assert,添加了調試輸出:
template <typename B, typename V>
static void test_assert(std::string description, B benchmark, V value)
{
std::ostringstream full_description;
full_description << description
<< " : { " << "benchmark" << ", " << "value" << " }"
<< " = { " << typeid(B).name() << ", " << typeid(V).name() << " }"
<< " , { " << benchmark << ", " << value << " }";
// N2Py6StringE, PKc i.e. Py::String and const char* (Pointer to Konst Char)
std::cout << typeid(B).name() << ", " << typeid(V).name() << std::endl;
V b_as_v{static_cast<V>(benchmark)};
// wtf? b_as_v: \352\277_\377 -- should be "ABC"
std::cout << "b_as_v: " << b_as_v << std::endl; // Y
if(b_as_v == value)
std::cout << " PASSED: " << full_description.str() << std::endl;
else
throw TestError(full_description.str());
}
正是這種b_as_v{static_cast<V>(benchmark)};
被扔我,因爲如果我單步執行到它,它正確地把我帶到字符串的「轉換爲const char *」操作,執行其職責正確:
class String : Object {
explicit operator const char*() const
{
std::string s{ as_std_string() };
const char* c{ s.c_str() };
// c before return: ABC
std::cout << "c before return: " << c << std::endl; // X
return c;
}
:
現在,這是奇怪的事情:如果行X到位,線Y報道什麼: 'b_as_v:'
行刪除它,Y行報告原始:'b_as_v:\ 352 \ 277_ \ 377'
事實上,只需打印std::cout << std::endl; // X'
X足以清除Y的輸出(但是,將X'移動到緊挨着Y恢復原來的行爲)。
所以看來觀察行爲會改變返回值。
heisenbug>:|
而這兩種行爲都不是理想的行爲。
另一個奇怪之處在於,如果我將粘貼從Xcode控制檯複製到SO文本編輯窗口,那麼在'\ 352 \ 277_ \ 377'的末尾會有一個額外的Unicode字符複製到剪貼板。
即使我只選擇最後7
它仍然副本劃過,即使它不佔用在Xcode的控制檯中的空白。
(這個額外的字符不會顯示在SO問題上,實際上當我重新打開編輯問題時,它不再存在,它不是 換行符 - 我測試過的複製粘貼-ing分詞在特定行的最後一個字符)
我試圖創建一個測試用例,但可悲的是,我所期望的執行:http://ideone.com/gbyU6Y
感謝T.C.,這是否意味着我可以安全地返回一個const char *的唯一方法是通過malloc - 它,並要求消費者隨後釋放它? – 2014-12-02 11:46:49
@Pi或者在你的'String'類中存儲'std :: string'。或者只是返回一個'std :: string',讓消費者調用'.c_str()'。 – 2014-12-02 11:48:26