我目前有一个函数用于返回T(模板化函数)。所以我一直认为它必须返回一个值,但我最近偶然发现了一些东西。
#define PRINTERROR(msg) \
std::cout << msg << "\n\tFILE: " << __FILE__ << "\n\tLINE: " << __LINE__ << "\n\tTIME: " << __TIME__ << std::endl << std::endl;
这......
template<class T>
T& Container_Vector<T>::GetFirstItem()
{
#ifdef CONTAINER_VECTOR_ERROR_CHECKING_ON
if (m_iCurrentSize > 0)
{
return m_pItems[0];
}
else
{
PRINTERROR("ERROR: Attempting to retrieve item from an empty vector container");
}
#else
return m_pItems[0];
#endif
}
当我单步执行代码试图测试msg是否输出并且错误检查是否在第一次检查(m_iCurrentSize&gt; 0)失败时,打印消息然后它似乎跳转到函数的末尾“ “什么也没有回来?
通常我会收到编译错误,说它必须返回一些东西。这里发生了什么,可以吗?
虽然它实际上没有逐步进入任何返回T的东西,但它确实会返回一些内容,也许是一个随机的内存地址。
答案 0 :(得分:3)
return
阻止PRINTERROR
之后,您遗漏了#ifdef
。不这样做会导致未定义的行为。您必须在函数末尾返回适当的值。
(这样的逻辑错误可以在编译时捕获,并设置了适当的标志。例如,在g ++中你可以使用-Wall
。)
答案 1 :(得分:1)
首先,预处理在编译之前进行。对于您的编译器,代码看起来像 -
如果定义了CONTAINER_VECTOR_ERROR_CHECKING_ON
:
template<class T>
T& Container_Vector<T>::GetFirstItem()
{
if (m_iCurrentSize > 0)
{
return m_pItems[0];
}
else
{
PRINTERROR("ERROR: Attempting to retrieve item from an empty vector container");
}
}
如果未定义CONTAINER_VECTOR_ERROR_CHECKING_ON
:
template<class T>
T& Container_Vector<T>::GetFirstItem()
{
return m_pItems[0];
}
你的第一个案例在所有分支上都没有回报,你应该至少得到一个警告。 MSVS不报告编译错误,但它确实返回警告。您获得的随机数只是函数退出前返回寄存器中的最后一个值。
答案 2 :(得分:0)
这是未定义的行为,如果CONTAINER_VECTOR_ERROR_CHECKING_ON
已定义且!( m_iCurrentSize > 0 )
则您没有撤回任何内容。您可能会收到警告,但不会出现错误,因为您确实有一个条件return
。在这种情况下,函数返回垃圾,之后堆栈可能已损坏。
答案 3 :(得分:0)
遗憾的是,省略从函数返回值不是编译错误。
编译器可能发出诊断消息(例如,如果使用-Wall
选项进行编译,则会执行g ++),但这不是强制性的。
省略返回值是编译器编写者可以自由地假设程序员永远不会做的事情,如果程序执行它,标准说编译器可以自由地忽略问题并且发生任何事情(未定义的行为)。它始终是程序员的错。
在x86架构上通常,如果函数返回一个真正的“本机”类型(例如char
或{{1},那么你会得到一些奇怪的值。如果该函数是例如返回一个类实例(例如int
),那么它可能会适合于寄存器而您可能会导致内存损坏或崩溃。但是请注意,任何关于未定义行为发生的事情的猜测只是......即纯粹的推测,因为C ++语言规范可能会发生任何。