在OS X上,简单的C ++程序给出不正确的结果(这是命令行选项'c ++ 03'vs'c ++ 11'的结果) [英] On OS X, simple C++ program gives incorrect results (which are a result of command-line options 'c++03' vs 'c++11')

查看:110
本文介绍了在OS X上,简单的C ++程序给出不正确的结果(这是命令行选项'c ++ 03'vs'c ++ 11'的结果)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个简单的程序(在Linux上编译时)将CORRECTLY给出两个不同的答案,基于是否使用 -std = c ++ 0x 编译。



问题:我无法在OS X(Mountain Lion,10.8 SDK)上重现相同的东西。
我缺少什么?

  #include< iostream> 
#include< sstream>

class Thing:public std :: ostringstream
{
public:
Thing():std :: ostringstream(){}
virtual〜Thing (){std :: cerr<< str(); }
};

int main(int argc,const char * argv []){
Thing()< Hello<< std :: endl;
return 0;
}






,请执行以下操作(在Linux上,只是为了看它应该如何工作):

  g ++ main.cpp 
> ./a.out
0x401471






 > g ++ -std = c ++ 0x main.cpp 
> ./a.out
Hello






第一个将打印一个十六进制地址,第二个将打印Hello。这是正确的行为,是因为操作符< 解析为两个不同的东西(在C ++ 03中没有右值引用,所以你去) p>

现在,在OS X上尝试同样的操作:






 > xcrun c + + main.cpp 
> ./a.out
0x10840dd88

(这正确地产生了十六进制输出。 p>




 > xcrun c ++ -std = c ++ 0x main.cpp 
> ./a.out
0x10840dd88

(糟糕...还是十六进制输出。






注意:版本的编译器在这里:

 > xcrun c ++ --version 
Apple clang版本4.1(标签/ Apple / clang-421.11.66)(基于LLVM 3.1svn)
目标:x86_64-apple-darwin12.2.0
线程模型:posix

注意:这不是C ++问题本身,而是OS X构建问题。对于那些感兴趣的人,使用C ++ 03和C ++ 11产生不同结果的原因在下面的一个答案中突出显示。

解决方案

首先,行为的预期差异是因为运算符<<(std :: ostream& amp; const char *) overload函数模板专门化,但现在nevermind)有一个类型 std :: ostream& 的参数,并且一个左值引用只能绑定到一个左值,在你的例子中流是一个右值,使得不能使用过载。在C ++ 03中,意味着唯一可行的重载是 std :: ostream :: operator<<(const void *)成员函数,因为成员函数可以在rvalue对象上调用,因此该字符串以十六进制形式写为 void * 地址。在C ++ 11中有一个新的运算符<<(std :: ostream&& const T&)函数模板,允许写入右值流,到运算符<<(std :: ostream& amp; const char *)重载,因此输出字符串而不是十六进制地址。



在GNU / Linux上,你可能使用了一个相当新的GCC版本,它在编译器(g ++)和标准库(libstdc ++)中对C ++ 11有相当好的支持,因此它有运算符<<<(std :: ostream&&&&& amp;) overload and everything Just Works。



在OS X上,你可能使用Clang与GCC的标准库libstdc ++。 Xcode默认带有一个古代版本的GCC(4.2),而GCC 4.2的标准库不支持C ++ 11,所以没有运算符<< 对于右值流的重载。使用 -std = c ++ 0x 告诉Clang支持C ++ 11语言功能(如右值引用),但不会神奇地使GCC 4.2的库成长C ++ 11代码,当GCC 4.2发布时,标准委员会的眼睛甚至不是闪烁。而不是运送非史前libstdc ++苹果,而是写了自己的标准库实现去与LLVM和Clang项目。使用 -stdlib = libc ++ 告诉clang使用libc ++标准库实现,而不是古老的libstdc ++。最近编写的libc ++对于右值引用有运算符<< 重载。


This simple program (when compiled on Linux) will CORRECTLY give two different answers based on whether it's compiled with -std=c++0x or not.

Problem: I cannot reproduce the same thing on OS X (Mountain Lion, 10.8 SDK). What am I missing?

#include <iostream>
#include <sstream>

class Thing : public std::ostringstream
{
public:
    Thing() : std::ostringstream() {}
    virtual ~Thing() { std::cerr << str(); }
};

int main(int argc, const char * argv[]) {
    Thing() << "Hello" << std::endl;
    return 0;
}


To see what I mean, do the following (on Linux first, just to see how it should work):

> g++ main.cpp
> ./a.out
0x401471


> g++ -std=c++0x main.cpp
> ./a.out
Hello


The first will print a hex address, the second will print "Hello". This is correct behavior and is because the operator << resolves to two different things (there are no rvalue references in C++03 so there you go).

Now, try the same thing on OS X:


> xcrun c++ main.cpp
> ./a.out
0x10840dd88

(This correctly produces the hex output.)


> xcrun c++ -std=c++0x main.cpp
> ./a.out
0x10840dd88

(Oops... still the hex output... We are in C++11x mode, but perhaps the correct headers are not being used?)


NOTE: Version of the compiler is here:

> xcrun c++ --version
Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin12.2.0
Thread model: posix

NOTE: This is not a C++ issue per se, but rather an OS X build issue. For those who are interested, the reason that it produces different results with C++03 and C++11 is highlighted below in one of the answers.

解决方案

Firstly, the expected difference in behaviour is because the operator<<(std::ostream&, const char*) overload (it's actually a function template specialization, but nevermind for now) has a parameter of type std::ostream& and an lvalue reference can only bind to an lvalue, and in your example the stream is an rvalue so that overload can't be used. In C++03 that means the only viable overload is the std::ostream::operator<<(const void*) member function, because member functions can be called on rvalue objects, so the string is written out as a void* address in hexadecimal. In C++11 there is a new operator<<(std::ostream&&, const T&) function template that allows writing to rvalue streams, and forwards to the operator<<(std::ostream&, const char*) overload, so the string is output rather than a hex address.

On GNU/Linux you are presumably using a fairly recent GCC release, which has fairly good support for C++11 in both the compiler (g++) and the standard library (libstdc++) so it has the operator<<(std::ostream&&, const T&) overload and everything Just Works.

On OS X you are probably using Clang with GCC's standard library, libstdc++. Xcode ships with an ancient version of GCC by default (4.2) and the standard library from GCC 4.2 doesn't support C++11, so doesn't have the operator<< overload for rvalue streams. Using -std=c++0x tells Clang to support C++11 language features (such as rvalue references), but doesn't magically make GCC 4.2's library grow C++11 code that wasn't even a twinkle in the standard committee's eye when GCC 4.2 was released. Rather than shipping a non-prehistoric libstdc++ Apple instead wrote their own standard library implementation to go with LLVM and Clang projects. Using -stdlib=libc++ tells clang to use that libc++ standard library implementation instead of the ancient libstdc++. As libc++ was written recently it has the operator<< overload for rvalue references.

这篇关于在OS X上,简单的C ++程序给出不正确的结果(这是命令行选项'c ++ 03'vs'c ++ 11'的结果)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆