VC 仅在第一次调用时选择错误的运算符 << 重载。漏洞?
-
21-09-2019 - |
题
我花了一些时间删除所有不影响的代码,这是我的问题。
--- 文件.h ---
#include <fstream>
#include <string>
template <typename Element>
class DataOutput : public std::basic_ofstream<Element>
{
public:
DataOutput(const std::string &strPath, bool bAppend, bool bBinary)
: std::basic_ofstream<Element>(
strPath.c_str(),
(bAppend ? ios_base::app : (ios_base::out | ios_base::trunc)) |
(bBinary ? ios_base::binary : 0))
{
if (is_open())
clear();
}
~DataOutput()
{
if (is_open())
close();
}
};
class File
{
public:
File(const std::string &strPath);
DataOutput<char> *CreateOutput(bool bAppend, bool bBinary);
private:
std::string m_strPath;
};
--- 文件.cpp ---
#include <File.h>
File::File(const std::string &strPath)
: m_strPath(strPath)
{
}
DataOutput<char> *File::CreateOutput(bool bAppend, bool bBinary)
{
return new DataOutput<char>(m_strPath, bAppend, bBinary);
}
--- main.cpp ---
#include <File.h>
void main()
{
File file("test.txt");
DataOutput<char> *output(file.CreateOutput(false, false));
*output << "test"; // Calls wrong overload
*output << "test"; // Calls right overload!!!
output->flush();
delete output;
}
这是构建后的输出文件 cl
和选项 /D "WIN32" /D "_UNICODE" /D "UNICODE"
和跑步
--- 测试.txt ---
00414114test
基本上发生的是第一个 operator<<
打电话进来 main
绑定到成员方法
basic_ostream<char>& basic_ostream<char>::operator<<(
const void *)
而第二个(正确地)绑定到
basic_ostream<char>& __cdecl operator<<(
basic_ostream<char>&,
const char *)
从而给出不同的输出。
如果我执行以下任一操作,则不会发生这种情况:
- 排队
File::CreateOutput
- 改变
DataOutput
与非模板一Element=char
- 添加
*output;
在第一个之前operator<<
称呼
我认为这是不受欢迎的编译器行为是否正确?
对此有什么解释吗?
哦,我现在正在使用 VC7 来测试这个简化的代码,但我已经尝试了 VC9 和 VC8 中的原始代码,并且发生了同样的事情。
任何帮助甚至线索都表示赞赏
解决方案
看起来像一个编译器错误。您可能想尝试使用最新的 VC 编译器(目前是 VC10 Beta2),如果它没有修复,请与 VC 团队跟进(您将需要一个完整的独立存储库)。如果它已修复,您应该使用您找到的周围的工作并继续您的生活。
其他提示
这是一个编译器错误(不仅仅是看起来像一个),因为它为两个相同的语句生成不同的调用绑定
*output << "test"; // Calls wrong overload
*output << "test"; // Calls right overload!!!
然而, 编译器有其权利 这样做,因为你有
void main()
这意味着这不是一个有效的 C++ 程序(void main
在 C 中也是不允许的,并且它在 C 或 C++ 中从来都不是有效的)。所以,你一直运行编译无效源代码的结果。其结果可以是任何东西。
Visual C++ 编译器不诊断的事实 void main
只是 另一个编译器错误.
改变
DataOutput *output(file.CreateOutput(false, false));
到
DataOutput* 输出 = file.CreateOutput(false, false);它可能会起作用。但是为了使其成为一个合理的库函数,您不必在返回实际对象而不是指针后进行清理。