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


227

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

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


1
export키워드 의 의미를 제거 하시겠습니까? 코트 입을 게요
Steve Jessop

7
알다시피, 나는 그것을 '부족한 변화'와 같은 "부싱으로의 변화"라고 부르지 않을 것입니다.
Xeo

4
그러한 노조를 만드는 데 필요한 모든 서류가 고무 도장을 기다리는 중이라면 왜 안됩니까?
Dennis Zickefoose 2018 년

3
@Xeo : mystream.good()와 같지 bool(mystream)않습니까? good()플래그가 설정되어 있지 않으면 true입니다. 설정된 bool(mystream)경우에만 여전히 거짓 eofbit입니다. !mystream.fail()올바른 동등한 것입니다.
R. Martinho Fernandes

2
중재자 참고 사항 : " 질문이나 답변이있는 주제에 대한 의견을 적어주십시오. 질문이나 답변을 논의 할 때 토론은 바로 그 질문이나 답변에 관한 것이어야합니다. 일반적으로 토론은 스택 오버플로에 대해 건설적인 것이 아닙니다. 길항은 확실하지 않다. "
Tim Post

답변:


178

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에 유효하지 않습니다.


"내부 연결로 함수의 종속 호출을 허용합니다." 두 예제의 차이점에 대해 자세히 설명해 주시겠습니까? 분명히 뭔가 빠졌습니다.
Dennis Zickefoose 2018 년

@Dennis 변경 사항은 open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#561에 의해 도입되었습니다 . 사실에 대해서는 언급하지 않지만 "인스턴스화 컨텍스트"는 여전히 "동일한 번역 단위에서 템플릿 전문화의 인스턴스화 시점 이전에 선언 된 외부 연결을 가진 선언 세트"만으로 구성됩니다. 따라서 변경 내용은 정의 컨텍스트의 조회에만 영향을줍니다.
Johannes Schaub-litb

내 첫 번째 예에서 내부 연결 함수는 템플릿의 정의 컨텍스트에서 볼 수있었습니다. 두 번째 예에서 내부 연결 함수는 인스턴스화 컨텍스트의 일부 여야합니다. 그러나 그것이 없기 때문에 그것을 찾을 수 없습니다.
Johannes Schaub-litb

덧붙여서, 템플릿 정의 컨텍스트가 내부 연결로 함수를 찾는 것이 안전한 유일한 경우는 함수 템플릿 전문화가 하나의 TU (템플릿이 정의 된)에서 명시 적으로 인스턴스화되고 다른 모든 TU가 의존하는 경우입니다 그 명시 적 인스턴스화. 다른 모든 TU (다른 TU가 특수화를 직접 인스턴스화하는 경우)에서는 매번 템플리트 정의가 다른 (내부 링크) 기능을 사용하도록하여 ODR을 위반합니다.
Johannes Schaub-litb

따라서 인스턴스화 컨텍스트에 대한 제한을 유지 한 이유를 잘 모르겠습니다. 하나의 (명시 적) 인스턴스화 만 있고 인스턴스화는 인스턴스화 TU의 인스턴스화 컨텍스트에있는 내부 연결 함수를 사용합니다. 정의 컨텍스트와 마찬가지로. 덧붙여, 우리는 여전히했을 경우 생각 export하고 내가 생각하는 다른 TU가이 명시 적 인스턴스화에 의존 할 필요가 없습니다,하지만 템플릿 themselfs를 인스턴스화 할 수있다. 그런 다음 인스턴스화 컨텍스트에 내부 연결 함수가 표시되는지 여부에 차이가 있습니다.
Johannes Schaub-litb

28

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


9
auto키워드를 사용하고 있다면 코드에 문제가있는 것입니다. 왜 지구상에서 그것을 사용하겠습니까?
Elazar Leibovich

그것은 중요한 변화 가 아닙니다 . 유효한 모든 C ++ 03 사용은 autoC ++ 11에서도 유효합니다.
Drew Dormann

11
@DrewDormann int main() { auto int i = 0; return i; }은 완벽하게 유효한 C ++ 03이지만 C ++ 11의 구문 오류입니다. 컴파일러가 C ++ 03 모드에서 제공 할 수있는 유일한 경고는 호환성에 대한 경고입니다.

24

변화를 깨고?

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


21

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


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있습니다.


14

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

#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


13

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

예에서에서 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;
};

표준 라이브러리 객체에 명시 적 변환이 추가 된 경우 기존 암시 적 변환이 작동하지 않을 수 있습니다. 그러나 전환이 유효하지 않고 유용한 것을 수행하는 시나리오는 상상할 수 없습니다.
Dennis Zickefoose

소개는 기존을 대체 하기 때문에 주요 변경 사항 operator void*입니다.
R. Martinho Fernandes

@Dennis : Aaah, 이제 @Martinho의 의미를 봅니다. 그러나 사람들이 의도 한 것 이외의 다른 용도로 사용한 경우에만 중대한 변화가 될 것입니다.
Xeo

"하지만 그 자체로 잘못된 방식으로 사용되는 경우에만" bool ok = cin >> a; cout << "done reading" << endl; if (ok) { ... }-C ++ 03에는 실제로 아무 문제가 없지만 C ++ 11에서는 오류가되었습니다. (참고 : GCC 4.9에는 여전히 operator void*() constC ++ 11 모드에서 코드를 허용하는 이유가 있습니다.)

std::identity<T>C ++ 03의 일부가 아니기 때문에 C ++ 11에서 제거되지 않았습니다. C ++ 11 초안에 간략하게 존재했으며 표준화 전에 초안에서 제거되었습니다.
Howard Hinnant


7

이전 버전과의 호환성을 깨는 암시 적 이동 에 대한 많은 토론이있었습니다.

( 관련 토론이있는 오래된 페이지 )

주석을 읽으면 암시 적 이동 리턴도 주요 변경 사항입니다.


이러한 토론의 결과는 거의 모든 경우에 제거되었습니다. 남은 문제가 있습니까?
Dennis Zickefoose 2018 년

@ 데니스 : 예. 귀하의 질문은 이 후속 페이지
Ben Voigt

아, 모바일 페이지에 댓글이 표시되지 않았습니다. 어느 쪽이든, 그것은 훨씬 더 유용한 링크입니다 ... 표준화 프로세스의 역사적 이상은 관련이 없습니다 (첫 번째 초안을 사용하는 MSVC를 사용하지 않는 한).
Dennis Zickefoose 2018 년

@ 데니스 : 당신이 옳은 것 같아요. 내 답변에서 일부 링크를 움직였습니다.
Ben Voigt 2016 년

안타깝게도 cpp-next.com은 더 이상 존재하지 않습니다. 나중에 참조 할 수 있도록 웹 페이지는 web.archive.org에 의해 저장됩니다. 이전 버전호환성을 암시적인 이동관련 토론이있는 이전 페이지입니다 .
Max Truxa

6
struct x {
   x(int) {}
};

void f(auto x = 3) { }

int main() {
   f();
}

C ++ 03 : 유효합니다.

C ++ 0x : error: parameter declared 'auto'


2
@Xeo : 코드는 C ++ 03에서 유효합니다. 유형이 struct x있고 이름이없는 매개 변수입니다 .
Ben Voigt

나는 누군가를 붙잡기를 바라고 있었다. @Xeo가 댓글을 읽지 못해서 그의 댓글을 너무 빨리 삭제하지 않았 으면 좋겠다.
궤도에서 가벼움 레이스

@ Xeo : 문법을 파헤 치지 않고 auto가 유효한 키워드가 아니라고 확신합니다. 그렇다면 예상대로 작동하지만 제대로 정의하기가 어려울 수 있습니다.
Dennis Zickefoose 2018 년

당신이 날 잡았다 고하자. 문자 그대로 구조체를 무시했습니다. :)
Xeo

@Tomalek : Xeo는 C ++ 03에 암시 적 int가 없다는 것을 올바르게 지적했습니다.
Ben Voigt 2016 년

-4

언어 특징

  1. {}를 사용한 균일하고 일반적인 초기화
  2. 자동
  3. 협착 방지
  4. constexpr
  5. 루프 기반 범위
  6. nullptr
  7. 열거 형 클래스
  8. static_assert
  9. std :: initializer_list
  10. Rvalue 참조 (시맨틱 이동)
  11. >>
  12. 람다
  13. 다양한 템플릿
  14. 유형 및 템플릿 별칭
  15. 유니 코드 문자
  16. 긴 정수형
  17. alignas와 alignof
  18. 선언하다
  19. 원시 문자열 리터럴
  20. 일반화 된 포드
  21. 일반화 된 노동 조합
  22. 템플릿 인수로서의 로컬 클래스
  23. 접미 부 리턴 유형 구문
  24. [[carries_dependency]] 및 [[noreturn]]
  25. noexcept 지정자
  26. noexcept 연산자.
  27. C99 기능 :
    • 확장 적분 유형
    • 좁은 / 넓은 줄의 연결
    • _ _ STDC_HOSTED _ _
    • _ 프 래그 마 (X)
    • vararg 매크로 및 빈 매크로 인수
  28. _ _ func _ _
  29. 인라인 네임 스페이스
  30. 위임 생성자
  31. 동급 멤버 이니셜 라이저
  32. 기본 및 삭제
  33. 명시 적 변환 연산자
  34. 사용자 정의 리터럴
  35. Extern 템플릿
  36. 함수 템플릿의 기본 템플릿 인수
  37. 상속 생성자
  38. 재정의와 최종
  39. 더 단순하고 일반적인 SFINAE 규칙
  40. 메모리 모델
  41. thread_local

표준 라이브러리 구성 요소

  1. 컨테이너의 initializer_list
  2. 컨테이너의 시맨틱 이동
  3. forward_list
  4. 해시 컨테이너
    • unorder_map
    • unorder_multimap
    • unorder_set
    • unorder_multiset
  5. 자원 관리 포인터
    • unique_ptr
    • shared_ptr
    • weak_ptr
  6. 동시성 지원
    • 뮤텍스
    • 자물쇠
    • 조건 변수
  7. 더 높은 수준의 동시성 지원
    • packaged_thread
    • 미래
    • 약속
    • 비동기
  8. 튜플
  9. 정규식
  10. 난수
    • uniform_int_distribution
    • 정규 분포
    • random_engine
    • 기타
  11. int16_t, uint32_t 및 int_fast64_t와 같은 정수 유형 이름
  12. 정렬
  13. 예외 복사 및 다시 던지기
  14. 시스템 오류
  15. 컨테이너에 대한 emplace () 작업
  16. constexpr 함수
  17. noexcept 기능의 체계적인 사용
  18. 기능과 바인딩
  19. 문자열을 숫자 값으로 변환
  20. 범위가 지정된 할당 자
  21. 유형 특성
  22. 시간 유틸리티 : 기간 및 time_point
  23. 비율
  24. quick_exit
  25. move (), copy_if () 및 is_sorted ()와 같은 더 많은 알고리즘
  26. 가비지 콜렉션 ABI
  27. 원자

더 이상 사용되지 않는 기능

  1. 소멸자가있는 클래스의 사본 생성자 및 사본 할당 생성
  2. 문자열 리터럴을 char *에 지정하십시오.
  3. C ++ 98 예외 사양
    • unexcepted_handler
    • set_unexpected
    • get_unexpected
    • 예기치 않은
  4. 함수 객체 및 관련 함수
  5. auto_ptr
  6. 레지스터
  7. ++ 부울
  8. 수출
  9. C 스타일 캐스트

3
이것은 질문에 대답하지 않습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.