C ++コードはC ++ 03とC ++ 11の両方で有効ですが、異なることを行うことができますか?

301
Erik Sjölund 2014-04-14 09:12.

C ++コードがC ++ 03標準とC ++ 11標準の両方に準拠することは可能ですが、コンパイルする標準に応じて異なることを行いますか?

7 answers

286
example 2014-04-14 10:49.

答えは確かにイエスです。プラス面には次のものがあります。

  • 以前は暗黙的にオブジェクトをコピーしていたコードは、可能な場合は暗黙的にオブジェクトを移動するようになりました。

マイナス面として、いくつかの例が規格の付録Cにリストされています。ポジティブよりもネガティブなものの方がはるかに多いですが、それぞれが発生する可能性ははるかに低くなります。

文字列リテラル

#define u8 "abc"
const char* s = u8"def"; // Previously "abcdef", now "def"

そして

#define _x "there"
"hello "_x // Previously "hello there", now a user defined string literal

0の型変換

C ++ 11では、リテラルのみが整数のnullポインター定数です。

void f(void *); // #1
void f(...); // #2
template<int N> void g() {
    f(0*N); // Calls #2; used to call #1
}

整数除算とモジュロ後の丸められた結果

C ++ 03では、コンパイラは0または負の無限大に向かって丸めることができました。C ++ 11では、0に向かって丸める必要があります

int i = (-1) / 2; // Might have been -1 in C++03, is now ensured to be 0

ネストされたテンプレートの閉じ中括弧の間の空白>> vs >>

特殊化またはインスタンス化の内部では、>>代わりにC ++ 03の右シフトとして解釈される場合があります。ただし、これにより既存のコードが破損する可能性が高くなります:(http://gustedt.wordpress.com/2013/12/15/a-disimprovement-observed-from-the-outside-right-angle-brackets/から)

template< unsigned len > unsigned int fun(unsigned int x);
typedef unsigned int (*fun_t)(unsigned int);
template< fun_t f > unsigned int fon(unsigned int x);

void total(void) {
    // fon<fun<9> >(1) >> 2 in both standards
    unsigned int A = fon< fun< 9 > >(1) >>(2);
    // fon<fun<4> >(2) in C++03
    // Compile time error in C++11
    unsigned int B = fon< fun< 9 >>(1) > >(2);
}

オペレーターnewは、以外の例外をスローできるようになりましたstd::bad_alloc

struct foo { void *operator new(size_t x){ throw std::exception(); } }
try {
    foo *f = new foo();
} catch (std::bad_alloc &) {
    // c++03 code
} catch (std::exception &) {
    // c++11 code
}

ユーザーが宣言したデストラクタには、C ++ 11ではどのような重大な変更が導入されていますか? 例からの暗黙的な例外仕様のC ++ 11ではどのような重大な変更が導入されていますか?

struct A {
    ~A() { throw "foo"; } // Calls std::terminate in C++11
};
//...
try { 
    A a; 
} catch(...) { 
    // C++03 will catch the exception
} 

size() O(1)で実行するには、コンテナの数が必要になります。

std::list<double> list;
// ...
size_t s = list.size(); // Might be an O(n) operation in C++03

std::ios_base::failurestd::exceptionもう直接派生していません

直接基本クラスは新しいものですが、そうでstd::runtime_errorはありません。したがって:

try {
    std::cin >> variable; // exceptions enabled, and error here
} catch(std::runtime_error &) {
    std::cerr << "C++11\n";
} catch(std::ios_base::failure &) {
    std::cerr << "Pre-C++11\n";
}
56
chris 2014-04-14 10:27.

この記事フォローアップを紹介します。これは、>>両方でコンパイルしながら、C ++ 03からC ++ 11に意味を変更する方法の良い例を示しています。

bool const one = true;
int const two = 2;
int const three = 3;

template<int> struct fun {
    typedef int two;
};

template<class T> struct fon {
    static int const three = ::three;
    static bool const one = ::one;
};

int main(void) {
    fon< fun< 1 >>::three >::two >::one; // valid for both  
}

重要な部分は、main式であるの行です。

C ++ 03の場合:

1 >> ::three = 0
=> fon< fun< 0 >::two >::one;

fun< 0 >::two = int
=> fon< int >::one

fon< int >::one = true
=> true

C ++ 11の場合

fun< 1 > is a type argument to fon
fon< fun<1> >::three = 3
=> 3 > ::two > ::one

::two is 2 and ::one is 1
=> 3 > 2 > 1
=> (3 > 2) > 1
=> true > 1
=> 1 > 1
=> false

おめでとうございます。同じ式で2つの異なる結果が得られました。確かに、C ++ 03は、テストしたときにClangという警告フォームを思い付きました。

39
Shafik Yaghmour 2014-04-15 05:20.

はい、同じコードがC ++ 03とC ++ 11の間で異なる動作を引き起こす原因となる多くの変更があります。順序付けルールの違いにより、以前は定義されていなかった動作が明確に定義されるなど、いくつかの興味深い変更が行われます。

1.初期化子リスト内の同じ変数の複数の突然変異

非常に興味深いコーナーケースの1つは、イニシャライザリスト内の同じ変数の複数の突然変異です。次に例を示します。

int main()
{
    int count = 0 ;
    int arrInt[2] = { count++, count++ } ;

    return 0 ;
}

C ++ 03とC ++ 11の両方でこれは明確に定義されていますが、C ++ 03での評価順序は指定されていませんが、イニシャライザ内の複数のミューテーションは未定義の動作をリストしていますか?。したがってclang、C ++ 03モードでコンパイルすると、次の警告が表示されます(ライブで参照)。

warning: multiple unsequenced modifications to 'count' [-Wunsequenced]

    int arrInt[2] = { count++, count++ } ;

                           ^        ~~

ただし、C ++ 11では警告は表示されません(ライブを参照)。

2.新しいシーケンスルールにより、i = ++ i +1になります。C ++ 11で明確に定義されている

C ++ 03の後に採用された新しい順序付け規則は、次のことを意味します。

int i = 0 ;
i = ++ i + 1;

はC ++ 11で未定義の動作ではなくなりました。これは、欠陥レポート637で説明されています。順序付けルールと例が一致しません

3.新しい順序付けルールも++++ iを作成します。C ++ 11で明確に定義されている

C ++ 03の後に採用された新しい順序付け規則は、次のことを意味します。

int i = 0 ;
++++i ;

C ++ 11では未定義の動作ではなくなりました。

4.もう少し賢明な署名付き左シフト

C ++ 11のその後のドラフトには、N3485以下にリンクするものが含まれており、1ビットを符号ビット内または符号ビットを超えてシフトするという未定義の動作が修正されています。これは、欠陥レポート1457でもカバーされています。ハワード・ヒナントは、スレッドのこの変更の重要性についてコメントしました。左シフト(<<)はC ++ 11の負の整数の未定義の動作ですか?

5. constexpr関数は、C ++ 11ではコンパイル時定数式として扱うことができます。

C ++ 11では、次のようなconstexpr関数が導入されました。

constexpr指定子は、コンパイル時に関数または変数の値を評価できることを宣言します。このような変数と関数は、コンパイル時定数式のみが許可されている場合に使用できます。

C ++ 03にはconstexpr機能がありませんが、標準ライブラリはC ++ 11でconstexprとして多くの関数を提供するため、constexprキーワードを明示的に使用する必要はありません。たとえば、std :: numeric_limits :: minです。これは、たとえば次のように異なる動作につながる可能性があります。

#include <limits>

int main()
{
    int x[std::numeric_limits<unsigned int>::min()+2] ;
}

clangC ++ 03で使用xすると、これは可変長配列になります。これは拡張機能であり、次の警告が生成されます。

warning: variable length arrays are a C99 feature [-Wvla-extension]
    int x[std::numeric_limits<unsigned int>::min()+2] ;
         ^

C ++ 11std::numeric_limits<unsigned int>::min()+2では、コンパイル時定数式であり、VLA拡張を必要としません。

6. C ++ 11では、例外仕様はデストラクタに対して暗黙的に生成されます。

C ++ 11では、ユーザー定義のデストラクタにはnoexcept(true)noexceptデストラクタで説明されているように暗黙の仕様があるため、次のプログラムを意味します。

#include <iostream>
#include <stdexcept>

struct S
{
  ~S() { throw std::runtime_error(""); } // bad, but acceptable
};

int main()
{
  try { S s; }
  catch (...) {
    std::cerr << "exception occurred";
  } 
 std::cout << "success";
}

C ++ 11では呼び出しますstd::terminateが、C ++ 03では正常に実行されます。

7. C ++ 03では、テンプレート引数に内部リンケージを含めることができませんでした

これは、std :: sortが関数内で宣言されたCompareクラスを受け入れない理由でうまく説明されています。したがって、次のコードはC ++ 03では機能しないはずです。

#include <iostream>
#include <vector>
#include <algorithm>

class Comparators
{
public:
    bool operator()(int first, int second)
    {
        return first < second;
    }
};

int main()
{
    class ComparatorsInner : public Comparators{};

    std::vector<int> compares ;
    compares.push_back(20) ;
    compares.push_back(10) ;
    compares.push_back(30) ;

    ComparatorsInner comparatorInner;
    std::sort(compares.begin(), compares.end(), comparatorInner);

    std::vector<int>::iterator it;
    for(it = compares.begin(); it != compares.end(); ++it)
    {
        std::cout << (*it) << std::endl;
    }
}

ただし、現在clang、C ++ 03モードでこのコードを許可していますが、-pedantic-errorsフラグを使用しない限り、警告が表示されます。これは、ちょっと厄介です。ライブ確認してください

8. >>は、複数のテンプレートを閉じるときに不正な形式ではなくなりました

>>複数のテンプレートを閉じるために使用することは、もはや不正な形式ではありませんが、C ++ 03とC + 11で異なる結果をもたらすコードにつながる可能性があります。以下の例は、直角ブラケットと下位互換性から抜粋したものです。

#include <iostream>
template<int I> struct X {
  static int const c = 2;
};
template<> struct X<0> {
  typedef int c;
};
template<typename T> struct Y {
  static int const c = 3;
};
static int const c = 4;
int main() {
  std::cout << (Y<X<1> >::c >::c>::c) << '\n';
  std::cout << (Y<X< 1>>::c >::c>::c) << '\n';
}

C ++ 03での結果は次のとおりです。

0
3

およびC ++ 11の場合:

0
0

9. C ++ 11は、std :: vectorコンストラクターの一部を変更します

この回答から少し変更されたコードは、std :: vector:から次のコンストラクターを使用することを示しています。

std::vector<T> test(1);

C ++ 03とC ++ 11では異なる結果が生成されます。

#include <iostream>
#include <vector>

struct T
{
    bool flag;
    T() : flag(false) {}
    T(const T&) : flag(true) {}
};


int main()
{
    std::vector<T> test(1);
    bool is_cpp11 = !test[0].flag;

    std::cout << is_cpp11 << std::endl ;
}

10.集約イニシャライザーでの変換の絞り込み

C ++ 11では、集約イニシャライザーでのナローイング変換の形式が正しくなくgcc、C ++ 11ではデフォルトで警告が表示されますが、C ++ 11とC ++ 03の両方でこれが許可されているようです。

int x[] = { 2.0 };

これはドラフトC ++ 11標準セクション8.5.4 リスト初期化パラグラフ3でカバーされています

タイプTのオブジェクトまたは参照のリスト初期化は次のように定義されます。

次の箇条書きが含まれています(強調鉱山):

それ以外の場合、Tがクラス型の場合、コンストラクターが考慮されます。該当するコンストラクターが列挙され、オーバーロード解決(13.3、13.3.1.7)によって最適なコンストラクターが選択されます。引数のいずれかを変換するために絞り込み変換(以下を参照)が必要な場合、プログラムの形式が正しくありません。

これと他の多くのインスタンスは、ドラフトC ++標準セクションannex C.2 C ++およびISOC ++ 2003でカバーされています。また、以下が含まれます。

  • 新しい種類の文字列リテラル[...]具体的には、R、u8、u8R、u、uR、U、UR、またはLRという名前のマクロは、文字列リテラルに隣接している場合は展開されませんが、文字列リテラルの一部として解釈されます。 。例えば

    #define u8 "abc"
    const char *s = u8"def"; // Previously "abcdef", now "def"
    
  • ユーザー定義のリテラル文字列のサポート[...]以前は、#1は2つの個別の前処理トークンで構成され、マクロ_xが展開されていました。この国際規格では、#1は単一の前処理トークンで構成されているため、マクロは展開されません。

    #define _x "there"
    "hello"_x // #1
    
  • 整数/および%の結果の丸めを指定します[...]整数除算を使用する2003コードは、結果を0または負の無限大に丸めますが、この国際標準は常に結果を0に丸めます。

  • size()メンバー関数の複雑さが一定になりました[...] C ++ 2003に準拠する一部のコンテナー実装は、この国際標準で指定されたsize()要件に準拠しない場合があります。std :: listなどのコンテナをより厳しい要件に調整するには、互換性のない変更が必要になる場合があります。

  • std :: ios_base :: failureの基本クラスを変更する[...] std :: ios_base :: failureはstd :: exceptionから直接派生しなくなりましたが、std :: system_errorから派生するようになりました。 std :: runtime_error。std :: ios_base :: failureがstd :: exceptionから直接派生していることを前提とする、有効なC ++ 2003コードは、この国際標準では異なる方法で実行される可能性があります。

35

潜在的に危険な後方互換性のない変更の1つは、などのシーケンスコンテナのコンストラクタstd::vector、特に初期サイズを指定するオーバーロードです。C ++ 03では、デフォルトで構築された要素をコピーしましたが、C ++ 11では、それぞれをデフォルトで構築します。

この例を考えてみましょう(boost::shared_ptr有効なC ++ 03になるように使用します)。

#include <deque>
#include <iostream>

#include "boost/shared_ptr.hpp"


struct Widget
{
  boost::shared_ptr<int> p;

  Widget() : p(new int(42)) {}
};


int main()
{
  std::deque<Widget> d(10);
  for (size_t i = 0; i < d.size(); ++i)
    std::cout << "d[" << i << "] : " << d[i].p.use_count() << '\n';
}

C ++ 03ライブの例

C ++ 11ライブの例

その理由は、C ++ 03が「サイズとプロトタイプ要素の指定」と「サイズのみの指定」の両方に次のように1つのオーバーロードを指定したためです(簡潔にするためにアロケーター引数は省略されています)。

container(size_type size, const value_type &prototype = value_type());

これは常にprototypeコンテナsize時間にコピーされます。したがって、1つの引数だけで呼び出されるとsize、デフォルトで作成された要素のコピーが作成されます。

C ++ 11では、このコンストラクターの署名が削除され、次の2つのオーバーロードに置き換えられました。

container(size_type size);

container(size_type size, const value_type &prototype);

2つ目は以前と同じように機能しsizeprototype要素のコピーを作成します。ただし、最初の要素(size引数のみが指定された呼び出しを処理するようになりました)は、デフォルトで各要素を個別に作成します。

この変更の理由についての私の推測は、C ++ 03オーバーロードは移動専用要素タイプでは使用できないということです。しかし、それでもそれは重大な変化であり、それについて文書化されることはめったにありません。

20
Anton Golov 2014-04-14 22:15.

からの読み取りに失敗した結果std::istreamが変更されました。 CppReferenceはそれをうまく要約しています:

抽出が失敗した場合(たとえば、数字が期待される場所に文字が入力された場合)、value変更されずに残さfailbitれて設定されます。(C ++ 11まで)

抽出に失敗した場合、ゼロが書き込まれvaluefailbit設定されます。抽出の結果、値が大きすぎたり小さすぎたりして収まらないvalue場合、std::numeric_limits<T>::max()またはstd::numeric_limits<T>::min()書き込まれてfailbitフラグが設定されている場合。(C ++ 11以降)

これは主に、新しいセマンティクスに慣れていて、C ++ 03を使用して記述しなければならない場合に問題になります。以下は特に良い習慣ではありませんが、C ++ 11で明確に定義されています。

int x, y;
std::cin >> x >> y;
std::cout << x + y;

ただし、C ++ 03では、上記のコードは初期化されていない変数を使用しているため、動作が定義されていません。

15
uwedolinsky 2014-04-15 05:19.

このスレッドC ++ 03とC ++ 0xの違いがあれば、実行時に検出できます。たとえば、C ++ 11参照の折りたたみを利用して、言語の違いを判断するための例(そのスレッドからコピー)があります。

template <class T> bool f(T&) {return true; } 
template <class T> bool f(...){return false;} 

bool isCpp11() 
{
    int v = 1;
    return f<int&>(v); 
}

およびc ++ 11では、ローカル型をテンプレートパラメータとして使用できます。

template <class T> bool cpp11(T)  {return true;} //T cannot be a local type in C++03
                   bool cpp11(...){return false;}

bool isCpp0x() 
{
   struct local {} var; //variable with local type
   return cpp11(var);
}
7
StackedCrooked 2014-04-16 21:41.

別の例を次に示します。

#include <iostream>

template<class T>
struct has {
  typedef char yes;
  typedef yes (&no)[2];    
  template<int> struct foo;    
  template<class U> static yes test(foo<U::bar>*);      
  template<class U> static no  test(...);    
  static bool const value = sizeof(test<T>(0)) == sizeof(yes);
};

enum foo { bar };

int main()
{
    std::cout << (has<foo>::value ? "yes" : "no") << std::endl;
}

プリント:

Using c++03: no
Using c++11: yes

Coliruで結果を見る

Related questions

MORE COOL STUFF

Reba McEntire は、彼女が息子の Shelby Blackstock と共有する「楽しい」クリスマスの伝統を明らかにしました:「私たちはたくさん笑います」

Reba McEntire は、彼女が息子の Shelby Blackstock と共有する「楽しい」クリスマスの伝統を明らかにしました:「私たちはたくさん笑います」

Reba McEntire が息子の Shelby Blackstock と共有しているクリスマスの伝統について学びましょう。

メーガン・マークルは、自然な髪のスタイリングをめぐってマライア・キャリーと結ばれました

メーガン・マークルは、自然な髪のスタイリングをめぐってマライア・キャリーと結ばれました

メーガン・マークルとマライア・キャリーが自然な髪の上でどのように結合したかについて、メーガンの「アーキタイプ」ポッドキャストのエピソードで学びましょう.

ハリー王子は家族との関係を修復できるという「希望を持っている」:「彼は父親と兄弟を愛している」

ハリー王子は家族との関係を修復できるという「希望を持っている」:「彼は父親と兄弟を愛している」

ハリー王子が家族、特にチャールズ王とウィリアム王子との関係について望んでいると主張したある情報源を発見してください。

ワイノナ・ジャッドは、パニックに陥った休暇の瞬間に、彼女がジャッド家の家長であることを認識しました

ワイノナ・ジャッドは、パニックに陥った休暇の瞬間に、彼女がジャッド家の家長であることを認識しました

ワイノナ・ジャッドが、母親のナオミ・ジャッドが亡くなってから初めての感謝祭のお祝いを主催しているときに、彼女が今では家長であることをどのように認識したかを学びましょう.

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セント ヘレナ島のジェイコブズ ラダーは 699 段の真っ直ぐ上る階段で、頂上に到達すると証明書が発行されるほどの難易度です。

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

世界最小のマルチツールを15ドルでキーチェーンに追加

世界最小のマルチツールを15ドルでキーチェーンに追加

爪| $ 15 | マルボロ&ケインザクロー| $ 15 | Malboro&Kane世界最小のマルチツールであるTheClawをたった15ドルで手に入れましょう。男の子と一緒に冷たいものを割って開けたり、ネジを締めたり、Amazonパッケージを細断したりする場合でも、この悪い男の子はこれまでで最も便利な製品の1つです。

ワンダーウーマンの続編の悪役についてのより多くの噂

ワンダーウーマンの続編の悪役についてのより多くの噂

ワンダーウーマンとしてのガル・ガドット。WaywardPinesは正式に終了しました。

42,000試合で作られた球がスローモーションで燃えるのを見るのは魅力的な光景です

42,000試合で作られた球がスローモーションで燃えるのを見るのは魅力的な光景です

人が2つのマッチを接着するように導くものは何ですか?何があなたをマッチに打ち続け、構造が湾曲していることを発見するのですか?42,000のボールを作るまで、試合を続けなければならない理由は何ですか?しかし、何よりも、これほど魅力的なショーである可能性はどのようにありますか?私はあなたをだますつもりはありません、次に私たちがあなたに残すのは、あなたや私のような人が自由な時間を過ごすことを決定するビデオですボールを作るために必要な試合数を確認します(答えは42です。

サクラメントビーが1950万人のカリフォルニア州の有権者記録を漏らし、ハッカーによって即座に侵害された

サクラメントビーが1950万人のカリフォルニア州の有権者記録を漏らし、ハッカーによって即座に侵害された

写真:AP先月、カリフォルニアの地元新聞が1,900万件以上の有権者記録をオンラインで公開しました。Gizmodoは今週、明らかなランサムウェア攻撃中にレコードが侵害されたことを確認しました。

米国のフィギュア スケートは、チーム イベントでの最終決定の欠如に「苛立ち」、公正な裁定を求める

米国のフィギュア スケートは、チーム イベントでの最終決定の欠如に「苛立ち」、公正な裁定を求める

ロシアのフィギュアスケーター、カミラ・バリエバが関与したドーピング事件が整理されているため、チームは2022年北京冬季オリンピックで獲得したメダルを待っています。

Amazonの買い物客は、わずか10ドルのシルクの枕カバーのおかげで、「甘やかされた赤ちゃんのように」眠れると言っています

Amazonの買い物客は、わずか10ドルのシルクの枕カバーのおかげで、「甘やかされた赤ちゃんのように」眠れると言っています

何千人ものAmazonの買い物客がMulberry Silk Pillowcaseを推奨しており、現在販売中. シルクの枕カバーにはいくつかの色があり、髪を柔らかく肌を透明に保ちます。Amazonで最大46%オフになっている間にシルクの枕カバーを購入してください

パデュー大学の教授が覚醒剤を扱った疑いで逮捕され、女性に性的好意を抱かせる

パデュー大学の教授が覚醒剤を扱った疑いで逮捕され、女性に性的好意を抱かせる

ラファイエット警察署は、「不審な男性が女性に近づいた」という複数の苦情を受けて、12 月にパデュー大学の教授の捜査を開始しました。

コンセプト ドリフト: AI にとって世界の変化は速すぎる

コンセプト ドリフト: AI にとって世界の変化は速すぎる

私たちの周りの世界と同じように、言語は常に変化しています。以前の時代では、言語の変化は数年または数十年にわたって発生していましたが、現在では数日または数時間で変化する可能性があります。

SF攻撃で91歳のアジア人女性が殴られ、コンクリートに叩きつけられた

犯罪擁護派のオークランドが暴力犯罪者のロミオ・ロレンゾ・パーハムを釈放

SF攻撃で91歳のアジア人女性が殴られ、コンクリートに叩きつけられた

認知症を患っている 91 歳のアジア人女性が最近、47 番街のアウター サンセット地区でロメオ ロレンゾ パーハムに襲われました。伝えられるところによると、被害者はサンフランシスコの通りを歩いていたところ、容疑者に近づき、攻撃を受け、暴行を受けました。

ℝ

“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.

メリック・ガーランドはアメリカに失敗しましたか?

バイデン大統領の任期の半分以上です。メリック・ガーランドは何を待っていますか?

メリック・ガーランドはアメリカに失敗しましたか?

人々にチャンスを与えることは、人生で少し遅すぎると私は信じています。寛大に。

Language