C ++ 11에서 어떤 C ++ 숙어가 더 이상 사용되지 않습니까?


192

새로운 표준에는 새로운 방식의 일이 있으며 많은 방법이 기존 방식보다 좋지만 기존 방식은 여전히 ​​낫습니다. 새로운 표준은 이전 버전과의 호환성을 위해 공식적으로 많이 사용되지 않습니다. 따라서 남아있는 질문은 다음과 같습니다.

어떤 오래된 코딩 방식이 C ++ 11 스타일보다 확실히 열등하지 않으며, 대신 무엇을 할 수 있습니까?

이에 대한 답으로 "자동 변수 사용"과 같은 명백한 것을 건너 뛸 수 있습니다.


13
관용구를 폐기 할 수 없습니다 .
Pubby

6
허브 셔터의 이야기 : 기본 2012 간다에서이 덮여
bames53

5
더 이상 상수 값을 반환하지 않는 것이 좋습니다. 분명히 auto_ptr더 이상 사용되지 않습니다.
Kerrek SB

27
물론이지, 퍼비 C ++ 템플릿이 발명되기 전에는 템플릿을 만드는 매크로 기술이있었습니다. 그런 다음 C ++에서 추가했으며 이전 방식은 나쁜 것으로 간주되었습니다.
Alan Baljeu

7
이 질문은 실제로 Programmers.se로 옮겨 져야합니다.
Nicol Bolas

답변:


173
  1. 최종 클래스 : C ++ 11은 final클래스 파생을 방지하기 위해 지정자를 제공합니다.
  2. C ++ 11 람다는 명명 된 함수 객체 (functor) 클래스의 필요성을 크게 줄입니다.
  3. Move Constructor : std::auto_ptrrvalue 참조에 대한 일류 지원으로 인해 더 이상 작업이 필요하지 않은 마법의 방법 .
  4. Safe bool : 앞에서 언급했습니다. C ++ 11의 명시 적 연산자는이 일반적인 C ++ 03 관용구를 제거합니다.
  5. 열 박음 : 많은 C ++ 11 STL 컨테이너는 shrink_to_fit()멤버 함수를 제공 하므로 임시로 교체 할 필요가 없습니다.
  6. 임시 기본 클래스 : 일부 오래된 C ++ 라이브러리는 다소 복잡한 관용구를 사용합니다. 이동 의미론을 사용하면 더 이상 필요하지 않습니다.
  7. Type Safe Enum 열거 형은 C ++ 11에서 매우 안전합니다.
  8. 힙 할당 금지 : = delete구문은 특정 기능이 명시 적으로 거부되었다고 말하는 훨씬 직접적인 방법입니다. 이는 힙 할당 방지 (예 : =deletemember operator new), 복사, 할당 방지 등에 적용됩니다.
  9. 템플릿 화 된 typedef : C ++ 11의 별칭 템플릿 은 간단한 템플릿 화 된 typedef의 필요성을 줄입니다. 그러나 복잡한 형식 생성기는 여전히 메타 함수가 필요합니다.
  10. 피보나치와 같은 일부 컴파일 타임 계산은 일반화 된 상수 표현식을 사용하여 쉽게 대체 할 수 있습니다.
  11. result_of: 클래스 템플릿 사용 result_of은로 대체해야합니다 decltype. 가능할 때 result_of사용 한다고 생각 합니다 decltype.
  12. 클래스 내 멤버 이니셜 라이저는 비 정적 멤버의 기본값을 기본값으로 사용하여 입력을 저장합니다.
  13. 새로운 C ++ 11 코드에서는 NULL로 재정의해야 nullptr하지만 STL의 강의에서 코드 에 대해 왜 결정했는지 알아보십시오.
  14. 식 템플릿 광신자는 C ++ 11에서 후행 반환 형식 함수 구문을 사용 하게되어 기쁩니다 . 더 이상 30 줄 길이의 리턴 유형이 없습니다!

거기서 멈출 것 같아요!


자세한 내용에 감사드립니다!
Alan Baljeu

7
큰 대답이지만 result_of목록에서 파업 합니다. 성가신에도 불구하고 typename그 전에 필요, 내 생각 typename result_of<F(Args...)::type가끔보다 쉽게 읽을 수 있습니다 decltype(std::declval<F>()(std::declval<Args>()...), 그리고 수용과 N3436 작업 용지에 그들 (의 장점이 될하는 데 사용 SFINAE 모두 작업 decltyperesult_of제공하지 않았다)
조나단 Wakely

14)에 대하여 나는 같은 코드를 두 번 작성하기 위해 매크로를 사용해야한다는 것을 여전히 울고있다. 한 번은 함수 본문과 decltype () 문에 대해 한 번 ...

2
이 주제는 이 Microsoft 페이지 에서 C ++ 언어에 대한 일반적인 소개의 "자세한 정보"기사로 링크되어 있지만이 주제는 고도로 전문화 된 주제입니다. 나는 간단한이 있음을 제안 할 수 있습니다 "이 항목은 C ++ 초보자를위한 아닙니다!" 주제 또는이 답변의 시작 부분에 조언이 포함됩니까?
Aacini

Re 12 : "In-class member initialize"-더 이상 사용되지 않는 관용구가 아닌 새로운 관용구입니까? 아마도 문장 순서를 바꾸시겠습니까? Re 2 : Functors는 객체가 아닌 유형 (특히 템플릿 매개 변수)을 전달할 때 매우 유용합니다. 그래서 그것은 단지의 일부 사용되지 않습니다 펑의 사용합니다.
einpoklum 2016 년

66

어느 시점에서 우리 const는 단지 가치가 아니라 가치로 돌아 가야한다고 주장했다 .

const A foo();
^^^^^

이것은 C ++ 98 / 03에서 대부분 무해했으며 다음과 같은 몇 가지 버그를 발견했을 수도 있습니다.

foo() = a;

그러나 constC ++ 11에서는 이동 의미론을 금지하기 때문에 return by by 가 금기입니다.

A a = foo();  // foo will copy into a instead of move into it

휴식을 취하고 코딩하십시오.

A foo();  // return by non-const value

9
그러나 이제 함수에 참조 한정자를 사용하면 예방할 수있는 실수를 잡을 수 있습니다. 위의 경우와 같이 A& operator=(A o)&대신 정의하십시오 A& operator=(A o). 이것들은 어리석은 실수를 방지하고 클래스가 기본 유형과 비슷하게 동작하며 이동 의미를 막지 않습니다.
Joe

61

포기 0하고 NULL찬성 하자마자 nullptr그렇게하십시오!

제네릭이 아닌 코드에서 사용 0하거나 NULL그렇게 큰 것은 아닙니다. 그러나 일반 코드에서 null 포인터 상수를 전달하기 시작하면 상황이 빠르게 바뀝니다. 당신이 통과하면 0A를 template<class T> func(T) Tint로서 추론 도착 int하지 널 포인터 상수로. 그리고 그 후에 널 포인터 상수로 다시 변환 할 수 없습니다. 이것은 우주가 단지 사용했을 경우 존재하지 않는 문제에 대한 혼란으로 이어진다 nullptr.

C ++ (11)는 더 이상 사용하지 않는 0NULL널 포인터 상수있다. 그러나 마치 마치 마치 코딩해야합니다.


decltype (nullptr)이란 무엇입니까?

4
@GrapschKnutsch :입니다 std::nullptr_t.
Howard Hinnant

채택 할 새로운 관례가 아닌 관용구가 더 이상 사용되지 않을 때이를 다시 표현하도록 제안하십시오 (예 : " 널 포인터 사용 0또는 사용 NULL").
einpoklum 2016 년

38

안전한 바보 관용구explicit operator bool().

개인 복사 생성자 (boost :: noncopyable) → X(const X&) = delete

개인 소멸자와 가상 상속으로 최종 클래스 시뮬레이션class X final


좋고 간결한 예. 그 중 하나에는 "이디엄"이라는 단어가 들어 있습니다. 잘 정리
Sebastian Mach

2
와우, 나는 '안전한 부자 관용구'를 본 적이 없다. 그것은 매우 역겨운 것처럼 보인다! 나는 C ++ 11 이전 코드에서는 절대로 그것을 필요로하지 않기를 바란다 ...
boycy

24

C ++ 11에서 기본 알고리즘을 작성하지 않도록하는 것 중 하나는 표준 라이브러리에서 제공하는 알고리즘과 함께 람다를 사용할 수 있다는 것입니다.

나는 지금 그것들을 사용하고 있으며, 얼마나 많은 루프를 다시 쓰지 않고 count_if (), for_each () 또는 다른 알고리즘을 사용하여 원하는 일을 얼마나 자주 말하는지 믿을 수 없다.

완전한 C ++ 11 표준 라이브러리와 함께 C ++ 11 컴파일러를 사용하고 나면 표준 알고리즘을 사용하여 빌드하지 않는 것에 대한 더 이상 변명의 여지가 없습니다 . 람다는 그냥 죽입니다.

왜?

실제로 (알고리즘을 작성하는이 방법을 사용한 후) 실제로 의미를 알기 위해 암호를 해독해야하는 일부 루프보다 수행되는 것을 의미하는 간단한 단어로 작성된 것을 읽는 것이 훨씬 쉽다. 즉, 람다 인수를 자동으로 추론하면 구문을 원시 루프와 비교하기가 훨씬 쉬워집니다.

기본적으로 표준 알고리즘으로 만든 알고리즘을 읽는 것이 루프의 구현 세부 사항을 숨기는 단어가 훨씬 쉬워집니다.

나는 우리가 더 낮은 수준의 알고리즘을 만들었 기 때문에 더 높은 수준의 알고리즘 만 생각해야한다고 생각합니다.


8
실제로 좋은 변명이 있습니다. 당신이 사용하고있는 Boost.Range에게의 훨씬 좋네요 알고리즘을)
니콜 올가미

10
for_each람다를 사용하는 것이 루프에있는 람다의 내용과 함께 동등한 범위 기반 for 루프보다 낫다는 것을 알지 못합니다 . 코드는 다소 비슷해 보이지만 람다는 약간의 구두점을 추가합니다. boost::irange반복자를 사용하는 것보다 더 많은 루프에 적용 하는 것과 동등한 것을 사용할 수 있습니다 . 또한 범위 기반 for 루프는 유연성이 뛰어나 필요에 따라 ( return또는으로 break) 일찍 종료 할 수있는 반면 for_each던져야합니다.
Steve Jessop

5
@SteveJessop : 그럼에도 불구하고 범위 기반의 가용성은 for일반적인 it = c.begin(), const end = c.end(); it != end; ++it관용구를 소멸시킵니다.
벤 Voigt

7
@SteveJessop의 장점 중 하나 for_each루프를 기반으로 범위 알고리즘은 당신 것입니다 수 없습니다 breakreturn. 즉, 당신이 볼 때 for_each그러한 까다로운 것이없는 몸을 보지 않고 즉시 알 수 있습니다.
bames53

5
@Klaim : 구체적으로 예 std::for_each(v.begin(), v.end(), [](int &i) { ++i; });를 들어와 비교 하고 for (auto &i : v) { ++i; }있습니다. 융통성은 양날입니다 ( goto매우 융통성이 있습니다. 문제입니다). 내가 생각하지 않는 사용할 수 없다는 제약 break에서 for_each이 요구 여분의 상세를위한 버전을 보정 - 사용자 for_each여기가 IMO (가) 있다는 이론적 인 개념의 종류 실제 가독성과 편리함을 희생하는 for_each것입니다 원칙적으로 명확하고 개념 더 간단합니다. 실제로는 더 명확하거나 단순하지 않습니다.
Steve Jessop

10

swap자주 사용하지 않는 사용자 정의 버전을 구현해야합니다 . C ++ 03에서는 swap값 비싸고 던지는 것을 피하기 위해 효율적인 비 투척 이 필요한 경우가 종종 있으며 std::swap, 두 개의 사본을 사용하므로 swap종종 커스터마이징해야합니다. C ++에서는을 std::swap사용 move하므로 효율적이고 던지지 않는 이동 생성자 및 이동 할당 연산자를 구현하는 데 중점을 둡니다. 이것들에 대한 기본값은 종종 괜찮 기 때문에 C ++ 03보다 훨씬 적습니다.

일반적으로 어떤 관용구가 경험을 통해 만들어지기 때문에 어떤 관용구가 사용 될지 예측하기 어렵습니다. 필요한 경험이 아직 없기 때문에 내년에 "Effective C ++ 11"과 "C ++ 11 코딩 표준"이 3 년 안에있을 것으로 예상 할 수 있습니다.


1
나는 이것이 의심 스럽다. 권장되는 스타일은 이동 및 복사 구성에 스왑을 사용하는 것이지만 원형이기 때문에 std :: swap은 사용하지 않습니다.
Alan Baljeu

예. 그러나 이동 생성자는 일반적으로 사용자 정의 스왑을 호출하거나 본질적으로 동일합니다.
Inverse

2

나는 그 이름을 모르지만 C ++ 03 코드는 종종 다음과 같은 구문을 누락 된 이동 할당 대신 사용했습니다.

std::map<Big, Bigger> createBigMap(); // returns by value

void example ()
{
  std::map<Big, Bigger> map;

  // ... some code using map

  createBigMap().swap(map);  // cheap swap
}

이것은 swap상기 와 함께 복사 제거로 인한 복사를 피했다 .


1
귀하의 예에서 스왑은 불필요합니다. 복사 제거는 map어쨌든 반환 값을 구성 합니다. 당신이 보여주는 기술은 map단지 구성되는 것이 아니라 이미 존재 하는 경우에 유용합니다 . 이 예제는 "싼 기본 생성자"코멘트없이 더 잘 될 것 "// ..."그 건설 및 스왑 사이
조나단 Wakely

귀하의 제안에 따라 변경했습니다. 감사.
Andrzej

"큰"과 "큰"의 사용은 혼동됩니다. 키의 크기와 값 유형이 어떻게 중요한지 설명해보십시오.
einpoklum 2016 년

1

C ++ 11 표준을 사용하는 컴파일러가 더 이상 다음 코드에 오류가 발생하지 않음을 알았습니다.

std::vector<std::vector<int>> a;

아마도 연산자 >>를 포함하고 있기 때문에 춤을 추기 시작했습니다. 이전 버전에서는해야 할 일

std::vector<std::vector<int> > a;

설상가상으로, 이것을 디버깅해야한다면, 이것으로부터 나오는 에러 메시지가 얼마나 끔찍한 지 알 것입니다.

그러나 이것이 "분명한"것인지 모르겠습니다.


1
이 기능은 이전 C ++에서 이미 추가되었습니다. 또는 적어도 Visual C ++은 몇 년 전에 표준 토론에 따라 구현했습니다.
Alan Baljeu

1
@AlanBaljeu 물론 컴파일러 / 라이브러리에 많은 비표준 항목이 추가되고 있습니다. C ++ 11 이전에 "자동"변수 선언이있는 수많은 컴파일러가 있었지만 코드를 실제로 다른 것으로 컴파일 할 수 있는지 확신 할 수 없었습니다. 문제는 "이 작업을 수행 할 수있는 컴파일러가 있었는지"가 아니라 표준에 관한 것이 었습니다.
v010dya

1

값으로 반환해도 더 이상 문제가되지 않습니다. 이동 의미론 및 / 또는 리턴 값 최적화 (컴파일러에 따라 다름) 코딩 기능을 사용하면 오버 헤드 나 비용없이 (대부분의 경우) 더 자연 스럽습니다.


...하지만 어느 관용어가 더 이상 사용되지 않습니까?
einpoklum 2016 년

관용구는 아니지만 더 이상 필요하지 않은 좋은 습관이었습니다. 컴파일러에서도 RVO를 지원하며 선택 사항입니다. en.wikipedia.org/wiki/Return_value_optimization "C ++의 진화 초기 단계에서, 함수에서 클래스 유형의 객체를 효율적으로 반환 할 수없는 언어는 약점으로 간주되었습니다 ....."struct Data {char bytes [ 16]; }; void f (Data * p) {// * p에서 직접 결과 생성} int main () {Data d; f (& d); }
Martin A

나는 당신이 당신의 대답을 "가치에 의한 반환을 피하는 관습은 더 이상 관련성이 없다"등으로 표현해야 함을 암시하고 있었다.
einpoklum 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.