【发布时间】:2013-05-29 08:15:51
【问题描述】:
我目前正在将一个相当大的项目从 VS 2008 转换为 2012,并且在似乎执行条件运算符类型转换的方式上遇到了问题。
首先让我说我接受条件运算符的语义有些复杂,并意识到代码最初所做的可能不正确,但我对现在在 VS 2012 中发生的事情感到非常困惑,我想知道如果有人能准确解释为什么它会这样做。
class DummyString
{
wchar_t wchBuf[32];
public:
DummyString() { *wchBuf = 0; }
DummyString(int) { *wchBuf = 0; }
DummyString(const DummyString& ds) { *wchBuf = 0; }
operator const wchar_t*() const { return wchBuf; }
};
int _tmain(int argc, _TCHAR* argv[])
{
DummyString ds;
// note: the argc test is simply to stop the conditional operator
// being optimised away
const wchar_t* pPtr = (argc == 100) ? 0 : ds;
assert(pPtr == static_cast<const wchar_t*>(ds));
return 0;
}
在 VS 2008 中,上面的条件运算符将导致在 ds 上调用 operator const wchar_t*() 方法,并且断言不会触发。也就是说,它会将ds 隐式转换为const wchar_t*。
在 VS 2012 中,条件运算符导致以下行为:
- 临时的
DummyString是通过复制构造函数构造的 - 然后在该临时副本上执行到
const wchar_t*的转换
这会导致pPtr 指向一个被破坏的对象,并且断言当然会触发。
现在,如果我从类中删除 DummyString(int) 构造函数,则代码无法在 VS2012 中编译(没有从 'DummyString' 到 'int' 的转换)很明显 0 导致表达式被评估为 int 而不是指针。
但是在这种情况下,为什么不调用DummyString(int) 构造函数将0 转换为DummyString?
为什么编译器会创建ds 的副本,然后将其转换为 wchar_t*,而它可以很容易地对原始对象执行转换?
我很想开悟! :)
【问题讨论】:
-
您是否尝试过使用
nullptr而不是0,所以这两个操作数被明确地视为指针? -
是的,我在调查时确实尝试过,它导致构建错误:没有从 'DummyString' 到 'nullptr' 的转换
-
第二个和第三个操作数不是同一类型的左值,因此条件表达式的结果是从所选操作数构造的右值。在任何情况下,您都不应该期望结果与
DummyString和ds相同。
标签: c++ visual-c++ visual-studio-2012 c++11