C ++ 11에 도입 된 주요 변경 사항은 무엇입니까? C ++ 11의 적어도

나는 오래된 코드가 컴파일을 멈추게하는 C ++ 11의 적어도 하나의 변경 사항 : explicit operator bool()표준 라이브러리에 도입 하여의 이전 인스턴스를 대체 한다는 것을 알고 있습니다 operator void*(). 물론, 이것이 깨질 코드는 아마도 처음에는 유효하지 않은 코드 일 것입니다. 그럼에도 불구하고 여전히 중요한 변경 사항입니다.

다른 주요 변경 사항이 있습니까?



답변

FDIS에는 부록 C.2“C ++ 및 ISO C ++ 2003” 에 비 호환성 섹션이 있습니다.

여기에서 FDIS를 해석하여 SO 답변으로 적합하게 만드는 요약. 차이점을 설명하기 위해 내 예제를 추가했습니다.

라이브러리의 비 호환성이 몇 가지 있지만 그 의미를 정확히 알지 못하므로 다른 사람들이 자세히 설명 할 수 있습니다.

핵심 언어


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

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

새 키워드 : alignas, alignof, char16_t, char32_t, constexpr, decltype, noexcept, nullptr, static_assert 및 thread_local


long으로 표현할 수있는 것보다 큰 특정 정수 리터럴은 부호없는 정수 유형에서 부호있는 long long으로 변경 될 수 있습니다.


정수 나누기를 사용하는 유효한 C ++ 2003 코드는 결과를 0 또는 음의 무한대로 반올림하지만 C ++ 0x는 항상 결과를 0으로 반올림합니다.

(실제로 대부분의 사람들에게 호환성 문제는 아닙니다).


키워드 auto를 스토리지 클래스 지정자로 사용하는 유효한 C ++ 2003 코드 는 C ++ 0x에서 유효하지 않을 수 있습니다.


변환이 좁아지면 C ++ 03과 호환되지 않습니다. 예를 들어 다음 코드는 C ++ 2003에서는 유효하지만 double to int는 축소 변환이므로이 국제 표준에서는 유효하지 않습니다.

int x[] = { 2.0 };

암시 적으로 선언 된 특수 멤버 함수는 암시 적 정의의 형식이 잘못되었을 때 삭제 된 것으로 정의됩니다.

정의가 필요하지 않은 상황 (예 : 잠재적으로 평가되지 않은 설명)에서 이러한 특수 멤버 함수 중 하나를 사용하는 유효한 C ++ 2003 프로그램은 잘못 구성됩니다.

나에 의한 예 :

struct A { private: A(); };
struct B : A { };
int main() { sizeof B(); /* valid in C++03, invalid in C++0x */ }

이러한 크기의 트릭은 일부 SFINAE에서 사용되었으며 지금 변경해야합니다. 🙂


사용자 선언 소멸자는 암시 적 예외 사양이 있습니다.

나에 의한 예 :

struct A {
  ~A() { throw "foo"; }
};

int main() { try { A a; } catch(...) { } }

이 코드는 terminateC ++ 0x에서 호출 하지만 C ++ 03에서는 호출 되지 않습니다. A::~AC ++ 0x에서 의 암시 적 예외 사양은 입니다 noexcept(true).


포함 된 유효한 C ++ 2003 선언 export은 C ++ 0x에서 잘못 구성되었습니다.


유효한 C ++ 2003 표현식 >뒤에 바로 다른 표현식이 포함 되어 >이제는 두 개의 템플리트를 닫는 것으로 간주 될 수 있습니다.

C ++ 03에서는 >>항상 shift-operator 토큰이됩니다.


내부 연결로 함수의 종속 호출을 허용합니다.

나에 의한 예 :

static void f(int) { }
void f(long) { }

template<typename T>
void g(T t) { f(t); }

int main() { g(0); }

C ++ 03에서는을 호출 f(long)하지만 C ++ 0x에서는을 호출합니다 f(int). C ++ 03 및 C ++ 0x에서 다음 호출이 있습니다 f(B)(인스턴스화 컨텍스트는 여전히 extern linkage 선언 만 고려합니다).

struct B { };
struct A : B { };

template<typename T>
void g(T t) { f(t); }

static void f(A) { }
void f(B) { }

int main() { A a; g(a); }

f(A)외부 연결이 없기 때문에 더 나은 일치 가 이루어지지 않습니다.


라이브러리 변경

C ++ 0x의 C ++ 표준 라이브러리에 추가 된 식별자를 사용하는 유효한 C ++ 2003 코드는이 국제 표준에서 컴파일 또는 다른 결과를 생성하지 못할 수 있습니다.


#includes새로운 C ++ 0x 표준 라이브러리 헤더의 이름을 가진 헤더가이 국제 표준에서 유효하지 않은 유효한 C ++ 2003 코드 .


스왑이있을 것으로 예상되어 컴파일 된 유효한 C ++ 2003 코드는 <algorithm>다음을 포함해야합니다.<utility>


글로벌 네임 스페이스 posix는 이제 표준화를 위해 예약되어 있습니다.


유효한 C ++가 정의하는 것이 2003 코드 override, final, carries_dependency, 또는 noreturn매크로와 같은 C ++ 0X에 유효하지 않습니다.


답변

자동 키워드의 의미가 변경되었습니다.


답변

변화를 깨고?

당신이 사용하는 경우 음, 한 가지, decltype, constexpr, nullptr, 등의 식별자로 당신은 문제가 될 수 있습니다 …


답변

비 호환성 섹션에서 다루지 않는 일부 핵심 비 호환성 :


C ++ 0x는 이름이 템플리트 템플리트 매개 변수에 대한 인수로 전달되고 템플리트 유형 매개 변수에 전달 된 경우 유형으로 삽입 된 클래스 이름을 템플리트로 처리합니다.

이러한 시나리오에서 삽입 된 클래스 이름을 항상 유형으로 사용하는 경우 유효한 C ++ 03 코드가 다르게 작동 할 수 있습니다. 내 clang PR에서 가져온 예제 코드

template<template<typename> class X>
struct M { };

template<template<typename> class X>
void g(int = 0); // #1

template<typename T>
void g(long = 0); // #2

template<typename T>
struct A {
  void f() {
    g<A>(); /* is ambiguous in C++0x */
    g<A>(1); /* should choose #1 in C++0x */
  }
};

void h() {
  A<int> a;
  a.f();
}

C ++ 03에서 코드는 두 번째를 g두 번 호출합니다 .


C ++ 0x는 C ++ 03에 종속 된 일부 이름을 이제 비 종속으로 만듭니다. 또한 인스턴스화시 반복 될 현재 클래스 템플릿의 멤버를 참조하는 비 의존적 정규화 된 이름에 대한 이름 조회가 필요하며 이러한 이름이 템플릿 정의 컨텍스트에서 수행 된 것과 동일한 방식으로 조회되는지 확인해야합니다.

이 규칙으로 인해 지배 규칙에 의존하는 유효한 C ++ 03 코드가 더 이상 컴파일되지 않을 수 있습니다.

예:

struct B { void f(); };

template<typename T>
struct A : virtual B { void f(); };

template<typename T>
struct C : virtual B, A<T> {
  void g() { this->f(); }
};

int main() { C<int> c; c.g(); }

이 유효한 C ++ 03 코드 A<int>::f는 C ++ 0x에서 유효하지 않습니다. 인스턴스화 할 때 이름 조회가 A<int>::f와 반대로 발견 되어 B::f정의 조회와 충돌이 발생하기 때문입니다.

이 시점에서 이것이 FDIS의 결함인지 확실하지 않습니다. 위원회는이를 알고 있으며 상황을 평가할 것입니다.


마지막 부분이 기본 클래스를 나타내는 규정 된 이름의 규정 자의 마지막 부분에있는 식별자와 동일한 사용 선언은 선언을 사용하여 해당 이름의 멤버 대신 생성자의 이름을 지정합니다.

예:

struct A { protected: int B; };
typedef A B;

struct C : B {
  // inheriting constructor, instead of bringing A::B into scope
  using B::B;
};

int main() { C c; c.B = 0; }

위의 예제 코드는 C ++ 03에서는 잘 구성되어 있지만 C ++ 0x에서는 잘못 구성 A::B되어 main있습니다.


답변

스트림 추출 실패는 다르게 처리됩니다.

#include <sstream>
#include <cassert>

int main()
{
   std::stringstream ss;
   ss << '!';

   int x = -1;

   assert(!(ss >> x)); // C++03 and C++11
   assert(x == -1);    // C++03
   assert(x == 0);     // C++11
}

제안 변경

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3246.html#23

표준 참조

[C++03: 22.2.2.1.2/11]: 2 단계 처리 결과는 다음 중 하나 일 수 있습니다.

  • 2 단계에서 일련의 문자가 누적되어 (의 규칙에 따라 scanf) 유형의 값으로 변환 val됩니다. 이 값은에 저장 val되고 ios_base::goodbit에 저장됩니다 err.
  • 2 단계에서 누적 된 문자 순서로 인해 scanf입력 오류가보고되었을 수 있습니다. ios_base::failbit에 할당되어 err있습니다. [ed :에 저장된 것이 없습니다 val.]

[C++11: 22.4.2.1.2/3]: [..] 저장할 숫자 값은 다음 중 하나 일 수 있습니다.

  • 변환 함수가 전체 필드를 변환하지 못하면 0입니다 . ios_base::failbit에 할당되어 err있습니다.
  • 필드 값이 너무 큰 양성을 나타내는 경우 가장 긍정적 표현할 값은로 표현된다 val. ios_base::failbit에 할당되어 err있습니다.
  • 필드가로 표현하기에 너무 큰 음수를 나타내는 경우 부호가없는 정수 유형에 대해 가장 음의 표현 가능 값 또는 0 val. ios_base::failbit에 할당되어 err있습니다.
  • 그렇지 않으면 변환 된 값

결과 숫자 값은 val .

구현

  • C ++ 11에 대한 GCC 4.8의 올바른 출력 .

    어설 션`x == -1 ‘실패

  • C ++ 03에 대한 GCC 4.5-4.8 모든 출력 는 다음과 같습니다. 버그로 보입니다.

    어설 션`x == -1 ‘실패

  • Visual C ++ 2008 ExpressC ++ 03에 대해 올바르게 출력됩니다.

    어설 션 실패 : x == 0

  • Visual C ++ 2012 Express 가 C ++ 11에 대해 잘못 출력되어 구현 상태 문제인 것으로 보입니다.

    어설 션 실패 : x == 0


답변

명시 적 변환 연산자를 도입하면 어떤 변화가 있습니까? 이전 버전은 여전히 ​​이전과 마찬가지로 “유효”합니다.

예에서에서 operator void*() const로의 변경은 explicit operator bool() const끊임없는 변경이 될 수 있지만 그 자체로 잘못된 방식으로 사용되는 경우에만 가능합니다. 적합한 코드는 깨지지 않습니다.

이제 또 다른 주요 변경 사항은 집계 초기화 중에 축소 변환을 금지하는 것입니다 .

int a[] = { 1.0 }; // error

편집 : 기억하기 만하면 std::identity<T>C ++ 0x에서 제거됩니다 (주 참조). 유형을 종속시키는 편리한 구조체입니다. 구조체는 실제로 많은 일을하지 않기 때문에 수정해야합니다.

template<class T>
struct identity{
  typedef T type;
};

답변

더 효율적인 코드를 허용하지만 몇 가지 경우에 대해 이전 버전과의 호환성을 자동으로 깨뜨리는 컨테이너 라이브러리에는 수많은 변경이 있습니다.

예를 들어, std::vector기본 구성, C ++ 0x 및 주요 변경 사항을 고려하십시오 .