当(且仅当)我使用 Windows Server 2003 使用 /Og
和 /GL
标志编译我的程序时 DDK C++ 编译器(它在 WDK 7.1 和 Visual Studio 2010 上很好!),我在运行时遇到访问冲突:
#include <algorithm>
#include <vector>
template<typename T> bool less(T a, T b) { return a < b; }
int main()
{
std::vector<int> s;
for (int i = 0; i < 13; i++)
s.push_back(i);
std::stable_sort(s.begin(), s.end(), &less<const int&>);
}
当我将最后一行更改为
时,访问冲突消失 std::stable_sort(s.begin(), s.end(), &less<int>);
-- 换句话说,当我让我的项目被复制而不是仅仅被引用时,它就会消失。
(我没有进行任何类型的多线程。)
为什么会发生这样的事情?我是否通过 const &
调用了一些未定义的行为?
编译器标志:
/Og /GL /MD /EHsc
链接器标志:(无)
包含环境变量:
C:\WinDDK\3790.1830\inc\crt
LIB 环境变量:
C:\WinDDK\3790.1830\lib\crt\I386;C:\WinDDK\3790.1830\lib\wxp\I386
操作系统:Windows 7 x64
平台:32位编译报错(64位运行正确)
编辑:
我刚刚用 Windows XP DDK(即 C:\WinDDK\2600
)试了一下,我得到了:
error LNK2001: unresolved external symbol
"bool __cdecl less(int const &,int const &)" (?less@@YA_NABH0@Z)
但是当我将它从模板更改为常规函数时,它神奇地适用于两种编译器!
我怀疑这意味着我发现了一个错误,该错误在使用 DDK 编译器获取模板函数的地址时发生。如果是这种情况,或者这是我不知道的其他极端情况,您有什么想法吗?
最佳答案
我尝试使用 Windows Server 2003 DDK SP1 安装(非 SP1 DDK 目前尚不可用)。这对 80x86 使用 cl.exe 版本 13.10.4035。它似乎与您发现的问题相同。
如果您在调试器中单步执行代码(跟随使用 /FAsc
选项生成的 .cod 文件会更容易一些),您会发现 less<int const &>()
函数期望用指向 int
的指针调用传入的值 eax
和 edx
.但是,调用 less<int const&>()
的函数(名为 _Insertion_sort_1<>()
)调用它传递堆栈上的指针。
如果你打开模板化的less
函数转换为非模板函数,它期望参数在堆栈上传递,所以大家都很高兴。
更有趣的是当你改变 less<const int&>
时会发生什么成为less<int>
反而。没有崩溃,但也没有任何排序(当然,您需要更改程序以从未排序的 vector 开始才能真正看到这种效果)。那是因为当你改为 less<int>
less
函数不再取消引用任何指针 - 它期望实际的 int 值在寄存器中传递(在本例中为 ecx
和 edx
)。但是没有指针取消引用意味着没有崩溃。然而,来电者,_Insertion_sort_1
, 仍然在堆栈上传递参数,因此 less<int>
正在执行比较与 vector 中的值无关。
这就是正在发生的事情,但我真的不知道根本原因是什么 - 正如其他人所提到的,它看起来像是与优化相关的编译器错误。
由于该错误显然已被修复,因此报告它显然没有意义(该版本的 DDK 中的编译器对应于接近 VS 2003/VC 7.1 的东西)。
顺便说一句 - 我无法让你的示例完全干净地编译 - 为了让它完全构建,我必须包含 bufferoverflowu.lib
让堆栈检查内容链接,即使这样链接器也会提示“发现多个具有不同属性的'.rdata'部分”。我似乎记得这是一个可以安全忽略的警告,但我真的不记得了。不过,我认为这些都与错误无关。
关于c++ - 为什么这种访问冲突会发生在/Og 和/GL 标志上,并带有传递引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7237837/