VC选择了错误的运算符<<仅在第一次调用时重载。漏洞?
我花了一些时间删除所有不影响的代码,这是我的问题。
--- File.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;
};
--- File.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);
}
< em>--- 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"
并运行
--- test.txt ---
00414114test
基本上发生的情况是第一个 运算符<<<
main
中的 /code> 调用绑定到成员方法
basic_ostream<char>& basic_ostream<char>::operator<<(
const void *)
,而第二个调用(正确)绑定到
basic_ostream<char>& __cdecl operator<<(
basic_ostream<char>&,
const char *)
成员方法,从而给出不同的输出。
如果我执行以下任一操作,则不会发生这种情况:
- 内联
File::CreateOutput
- 将
DataOutput
更改为带有Element=char
的非模板> - 在第一个
运算符<<之前添加
call*output;
我认为这是不受欢迎的编译器行为是否正确?
对此有什么解释吗?
哦,我现在正在使用 VC7 来测试这个简化的代码,但我已经尝试了 VC9 和 VC8 中的原始代码,并且发生了同样的事情。
任何帮助甚至线索都表示赞赏
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是一个编译器错误(不仅仅是看起来像一个),因为它为两个相同的语句生成不同的调用绑定
但是,编译器有权利这样做,因为 这意味着
这不是一个有效的 C++ 程序(C 中也不允许使用 void main,并且它在 C 或 C++ 中从来都不是有效的)。所以,你一直运行编译无效源代码的结果。其结果可以是任何东西。
Visual C++ 编译器不诊断
void main
的事实只是另一个编译器错误。It is a compiler bug (not just looks like one) since it produces different call bindings for the two identical statements
However, the compiler is within its rights to do this, since you have
which means that this is not a valid C++ program (
void main
isn’t permitted in C either, and it has never been valid in C or C++). So, you have been running the result of compiling invalid source code. The result of that can be anything.The fact that the Visual C++ compiler does not diagnose
void main
is just another compiler bug.看起来像一个编译器错误。您可能想尝试使用最新的 VC 编译器(目前是 VC10 Beta2),如果它没有修复,请与 VC 团队跟进(您将需要一个完整的独立存储库)。如果它已修复,您应该使用您找到的周围的工作并继续您的生活。
Looks like a compiler bug. You might want to try with the latest VC compiler (which at the moment is VC10 Beta2), and if it's not fixed, follow up with the VC team (you'll need a complete self contained repo). If it is fixed, you should just use the work around you found and move on with your life.
更改
DataOutput *output(file.CreateOutput(false, false));
到
DataOutput* 输出 = file.CreateOutput(false, false);它可能会起作用。但是为了使其成为一个合理的库函数,您不必在返回实际对象而不是指针后进行清理。
change
DataOutput *output(file.CreateOutput(false, false));
to
DataOutput* output = file.CreateOutput(false, false); and it might work. But to make this a reasonable lib function you don't have to clean up after you should not return a pointer but an actual object.