C ++의 최악의 관행, 일반적인 실수


35

Linus Torvalds의이 유명한 rant을 읽은 후 실제로 C ++의 프로그래머에게 어떤 함정이 있는지 궁금했습니다. 나는 이 질문과 그 답변 에서 처리 된 오타 또는 잘못된 프로그램 흐름을 명시 적으로 언급 하지 않지만 컴파일러에서 감지하지 못하고 처음 실행할 때 명백한 버그를 일으키지 않는 더 높은 수준의 오류를 언급하고 있습니다. C에서는 불가능하지만 C ++에서는 코드의 전체 의미를 이해하지 못하는 신규 사용자가 수행 할 가능성이 있습니다.

또한 일반적으로 예상되지 않는 성능 저하가 큰 것으로 나타났습니다. 교수님이 내가 쓴 LR (1) 파서 생성기에 대해 한 번 말해 본 예 :

불필요한 상속 및 가상 인스턴스를 너무 많이 사용했습니다. 상속은 디자인을 훨씬 더 복잡하게 만들고 (RTTI (Run-time Type Inference) 하위 시스템으로 인해 비효율적 임) 구문 분석 테이블의 작업에 적합한 경우에만 사용해야합니다. 템플릿을 집중적으로 사용하기 때문에 실제로는 상속 할 필요가 없습니다. "


6
C / C ++에서 더 많은 불쾌한 오류 중 일부는 주로 C 유산 때문입니다 ... 정의되지 않은 동작, 수동 메모리 관리 등을 읽으십시오. 또한 교수의 조언은 가짜 / 잘못된 것 같습니다. C ++ 전문가)-템플릿 인스턴스화는 virtual함수에 대한 vtable이있는 일반 클래스를 생성해야 합니까?

8
교수님의 말을 잘못 기억하고 있거나 자신이 말한 것을 전혀 알지 못했습니다. 파생 클래스는 일반적으로 RTTI (AKA 리플렉션)를 사용하여 조회 할 필요가 없습니다. 가상 메소드를 사용하는 경우 코드는 디스패치에 대한 vtable 조회를 수행해야하지만 많은 프로세서에서 단일 ASM 명령어로 변환됩니다. 캐싱 문제로 인해 일정 속도가 느려질 수 있지만 가장 까다로운 사용 사례를 제외하고는 오버 헤드가 눈에 띄지 않을 것입니다. C ++를 피해야하는 많은 이유가 있지만 vtable 조회는 그중 하나가 아닙니다.
메이슨 휠러

5
@FelixDombek : 너무 일반적으로 말해서 전반적으로 적용됩니다. 교수의 인용은 방대한 양의 무지를 보여줍니다. 디자인 에 어떤 종류의 런타임 다형성이 필요한 경우 가상 함수를 사용하는 것이 가장 좋습니다. 필요하지 않을 때는 사용하지 마십시오. 예를 들어 파생 클래스를 사용하기 때문에 모든 메서드가 가상 일 필요는 없습니다.
Fred Nurk

5
@Mason Wheeler : RTTI에는 유형에 대한 정보가 포함되어있어 dynamic_cast성공 여부를 결정할 수있을 뿐 아니라 다른 사항은 거의 없지만 반사는 멤버 속성 또는 함수에 대한 정보를 검색 할 수있는 것을 포함하여 훨씬 더 많은 내용을 다루고 있습니다. C ++에 존재합니다.
David Rodríguez-dribeas

5
상속과 가상 함수가 큰 성능 저하가 아니기 때문에 교수의 의견은 다소 기만적입니다. 상속을 조금만 사용하는 것이 좋지만 효율성보다는 프로그램 구조의 문제입니다. 상속, 특히 보호 된 멤버에 대한 상속은 얻을 수있는만큼의 커플 링에 가깝고, 필요하지 않은 경우에는 사용하지 않아야합니다.
David Thornley

답변:


69

토발즈는 여기서 그의 엉덩이에 대해 이야기하고 있습니다.


좋아, 왜 그의 엉덩이에서 이야기하고 있니?

우선, 그의 rant는 실제로 rant rant는 아닙니다. 여기에는 실제 내용이 거의 없습니다. 그것이 정말로 유명하거나 심지어 온화하게 존경받는 유일한 이유는 그것이 리눅스 신에 의해 만들어 졌기 때문입니다. 그의 주요 주장은 C ++가 엉망이고 C ++ 사람들을 화나게하는 것을 좋아한다는 것입니다. 물론 그것에 대해 응답 할 이유가 전혀 없으며, 합리적인 논쟁이라고 생각하는 사람은 대화를 넘어선 것입니다.

그의 가장 객관적인 요점으로 보일 수있는 것 :

  • STL과 Boost는 아무리 쓸모가 없습니다. 당신은 바보예요.
  • STL과 Boost는 무한한 고통을 유발합니다. 분명히 그는 과다하게 과다 평가를 받았지만 그의 실제 진술은 무엇입니까? 모르겠어요 Spirit이나 다른 것에서 컴파일러 구토를 일으킬 때 문제를 파악하는 것은 매우 어려운 일이지만 void *와 같은 C 구문을 잘못 사용하여 UB를 디버깅하는 것보다 더 어렵지 않습니다.
  • C ++에서 권장하는 추상 모델은 비효율적입니다. <-무엇처럼? 그는 결코 확장하지 않으며, 자신이 의미하는 바에 대한 어떠한 예도 제공하지 않습니다. BFD. 나는 그가 말하는 것을 말할 수 없기 때문에 진술을 "반복"하려고하는 것은 아무 소용이 없습니다. C bigots의 일반적인 만트라이지만 더 이해하기 어렵거나 이해하기 쉽지 않습니다.
  • C ++를 올바르게 사용한다는 것은 C 측면으로 자신을 제한한다는 의미입니다. <-실제로 WORSE C ++ 코드는 이것을 수행하므로 그가 말하는 WTF를 여전히 알지 못합니다.

기본적으로 토발즈는 그의 엉덩이에서 이야기하고 있습니다. 어떤 것에 대해서도 명백한 논증이 없습니다. 그런 말도 안되는 것에 대한 진지한 반박을 기대하는 것은 단순한 바보입니다. 내가 말한 곳에서 확장 될 것으로 예상되는 것에 대한 반박에 대해 "확장"하라는 말을 듣고있다. 당신이 정말로, 솔직히 토발즈가 말한 것을 보라. 그가 실제로 아무 말도하지 않았다는 것을 알게 될 것이다.

신이 말한다고해서 그것이 임의의 보조가 말한 것보다 더 의미가 있거나 더 심각하게 받아 들여야한다는 것을 의미하지는 않습니다. 진실은, 하나님은 또 다른 무작위 보조입니다.


실제 질문에 대한 답변 :

아마도 최악의 가장 일반적인 C ++ 관행은 C와 같이 취급하는 것입니다. printf와 같은 C API 함수를 계속 사용하면 (C에서도 좋지 않은 것으로 간주 됨) strtok 등 제공된 힘을 활용하지 못할뿐만 아니라 더 타이트한 타입의 시스템에 의해, 그들은 "실제"C ++ 코드와 상호 작용하려고 할 때 필연적으로 추가적인 합병증을 초래합니다. 따라서 기본적으로 Torvalds가 조언하는 것과 정반대입니다.

STL과 Boost를 활용하여 컴파일 타임에 버그를 더 많이 감지하고 다른 일반적인 방법으로 인생을 더 편하게 만드는 방법을 배우십시오 (예를 들어 Boost 토크 나이 저는 유형이 안전하고 더 나은 인터페이스입니다). 템플릿 오류를 읽는 방법을 배워야한다는 것은 사실입니다. 처음에는 어려워하지만 (어쨌든 내 경험에 따르면) 런타임 동안 정의되지 않은 동작을 생성하는 무언가를 디버깅하는 것보다 C API가 만드는 것이 훨씬 쉽습니다. 아주 쉬운 일입니다.

C가 좋지 않다고 말할 수는 없습니다. 물론 C ++을 더 좋아합니다. C를 좋아하는 C 프로그래머 놀이에는 트레이드 오프와 주관적인 좋아가 있습니다. 또한 잘못된 정보와 FUD가 많이 떠 있습니다. C ++에 대해 더 많은 FUD와 잘못된 정보가 떠 다니고 있다고 말하지만이 점에서 편견이 있습니다. 예를 들어, C ++이 겪었던 "부풀림"및 "성능"문제는 실제로 대부분의 주요 문제는 아니며 실제로 실제 비율에서 벗어난 것입니다.

교수가 언급 한 문제에 관해서는 C ++에만 국한되지 않습니다. OOP (및 일반 프로그래밍)에서는 상속보다 컴포지션을 선호합니다. 상속은 모든 OO 언어에 존재하는 가장 강력한 결합 관계입니다. C ++는 더 강력하고 친근한 것을 하나 더 추가합니다. 다형성 상속은 추상화와 "is-a"관계를 나타내는 데 사용되어야하며 재사용에 사용해서는 안됩니다. 이것은 C ++에서 두 번째로 큰 실수이며 꽤 큰 실수이지만 언어와는 다릅니다. C # 또는 Java에서도 지나치게 복잡한 상속 관계를 만들 수 있으며 정확히 동일한 문제가 발생합니다.


1
아이러니하다. 2007 년 이후까지 git은 이식 가능한 버전의 Linux 만 실행했다. 글쎄, 유닉스와 비슷한 모든 시스템. 그런 다음 다시 자식 생성으로 이어지는 상황을 감안할 때, 나는 그에게 반대하지 않을 것입니다.
Chris K

9
Linus는 자신을 위해 일하고 싶은 좋은 C ++ 프로그래머를 찾는 데 어려움을 겪고 있습니다. 왜 궁금해? 나는 이것이 닭과 계란 유형의 문제라고 생각합니다.
보 퍼슨

19

저는 항상 C ++의 경험이 부족한 C와 클래스 프로그래머들에 의해 C ++의 위험이 과장되었다고 생각했습니다.

그렇습니다. C ++은 Java와 같은 것보다 선택하기가 어렵지만 최신 기술을 사용하여 프로그래밍하면 강력한 프로그램을 작성하는 것이 매우 쉽습니다. 솔직히이없는 것을 나 자바와 같은 언어에서보다 C ++에서 시간 프로그래밍의 훨씬 더 큰 어려움을, 나는 종종 나 자신은 내가 다른 언어로 디자인 템플릿과 RAII 같은 특정 C ++ 추상화 누락을 발견.

즉, C ++로 수년간의 프로그래밍을 한 후에도 매번 더 높은 수준의 언어로는 불가능한 정말 바보 같은 실수를 저지를 것입니다. C ++의 일반적인 함정은 객체 수명을 무시하는 것입니다. Java 및 C #에서는 일반적으로 객체 수명에 신경 쓸 필요가 없습니다. 모든 객체가 힙에 존재하고 마술 가비지 수집기에서 관리하기 때문입니다.

이제 현대 C ++에서는 일반적으로 객체 수명에 대해 크게 신경 쓸 필요가 없습니다. 객체의 수명을 관리하는 소멸자와 스마트 포인터가 있습니다. 시간의 99 %, 이것은 훌륭하게 작동합니다. 그러나 매번 당신은 매달려있는 포인터 (또는 참조)에 의해 망칠 것입니다. 예를 들어, 최근 Foo에 다른 객체에 대한 내부 참조 변수를 포함하는 객체 (이것이라고 부릅니다 Bar)가있었습니다 ( 이것을 호출하십시오 ). 어느 시점에서, 나는 어리석게 배열 Bar하여 범위를 벗어 Foo났지만 Foo소멸자는 결국 멤버 함수를 호출했습니다 Bar. 말할 것도없이, 일이 잘되지 않았다.

이제는 C ++을 비난 할 수 없습니다. 내 자신의 나쁜 디자인 이었지만 요점은 이런 종류의 일이 상위 수준의 관리되는 언어에서는 발생하지 않는다는 것입니다. 스마트 포인터 등을 사용해도 때때로 개체 수명에 대한 인식이 필요합니다.


* 관리중인 리소스가 메모리 인 경우입니다.


8
Java와 C #의 객체 수명에 대해 신경 쓰지 않아도됩니까? 그들의 GC는 기억을 돌보지 만, 그것은 나를 위해 RAII의 작은 부분 일뿐입니다. 예를 들어, 해당 언어가 가지고있는 다양한 "일회용"인터페이스를 살펴보십시오.
Fred Nurk

개체 수명에 관심을 갖는 자사의 I / O 라이브러리의 불편 디자인을 제외하고 자바에서 드문.
dan04

매달려있는 참조 문제는 내가 해결하려는 관심사입니다. 나는 블로그에서 그것을 해결하기위한 방향에 대한 토론을 시작했다 (포인터 약속). 기본적으로 나는 언어가 더 똑똑한 포인터를 사용할 수 있다고 생각합니다. 관심이 있다면 그 토론에 참여하십시오. 다른 사람은 없었습니다 ...하지만 만약 당신이 해결하고 싶은 무언가라면 ... 나는 실제로 시간의 10 % 이상 문제에 부딪칩니다.
Edward Strange

13

코드의 차이는 일반적으로 언어보다 프로그래머와 더 관련이 있습니다. 특히, 훌륭한 C ++ 프로그래머와 C 프로그래머는 모두 비슷하지만 (다른 경우에도) 솔루션이 될 것입니다. 이제 C는 언어로서의 간단한 언어이므로 코드가 실제로 수행하는 작업에 대한 추상화가 적고 가시성이 높아집니다.

그의 rant의 일부 (C ++에 대한 rants로 알려져 있음)는 더 많은 사람들이 C ++을 사용하고 일부 추상화가 숨기고 잘못된 가정을 실제로 이해하지 않고 코드를 작성한다는 사실을 기반으로합니다.


3
std::vector<bool>각 값 변경 을 반복하는 데 드는 비용은 얼마입니까? for ( std::vector<bool>::iterator it = v.begin(), end = v.end(); it != end; ++it ) { *it = !*it; }? 무엇에서 추상화되어 *it = !*it;있습니까?
David Rodríguez-dribeas

2
실수로 널리 비판되는 특정 언어 혐오를 선택하는 것은 불공평 할 수 있지만 ...
Fred Nurk

2
@Fred Nurk : std::vector<bool>잘 알려진 실수이지만, 논의되고있는 것의 정말 좋은 예입니다. 추상화는 좋지만, 숨기는 것을 조심해야합니다. 사용자 코드에서도 마찬가지입니다. 우선, 나는 흐름 제어 및 코드를 수행하기 위해 예외를 사용하여 C ++ 및 Java 사람들 모두를 보았다 실제로 구제 금융 예외 발사기 중첩 함수 호출과 같습니다 void endOperation();로 구현 throw EndOperation;. 훌륭한 프로그래머는 이러한 놀라운 구조 를 피할 수 있지만 사실은 그 구조를 찾을 수 있다는 것입니다.
David Rodríguez-dribeas

5
Torvalds의 요점 중 하나는 C ++ 대신 C를 선택하여 초보자를 멀리 할 수 ​​있으며 (C ++ 초보자가 더 많은 것으로 보입니다) C ++이 더 복잡할수록 학습 곡선이 가파르고 코너 케이스에서 넘어 질 가능성이 더 높습니다 .
David Rodríguez-dribeas

2
+1, 이것은 리누스가 정확히 불평하는 것입니다. 그는 안티 C ++ 인 것처럼 보이지만 실제로는 그렇지 않습니다. 그는 안티 C ++ 프로그래머 일뿐입니다.
greyfade

13

try/catch블록 남용 .

File file("some.txt");
try
{
  /**/

  file.close();
}
catch(std::exception const& e)
{
  file.close();
}

이것은 일반적으로 Java와 같은 언어에서 유래하며 사람들은 C ++에 finalize절이 없다고 주장합니다 .

그러나이 코드에는 두 가지 문제가 있습니다.

  • 에 존재하지 않는 파일은 실제로 사용할 수 없기 때문에, file전에 빌드 해야합니다 . 이로 인해 "스코프 누출"이 발생하여 닫힌 후에 볼 수 있습니다. 블록을 추가 할 수 있지만 ... : /try/catchclosecatchfile
  • 누군가가 와서 범위 return의 중간에를 추가 try하면 파일이 닫히지 않습니다 (그래서 사람들은 finalize절이 부족하다는 것을 암시합니다)

그러나 C ++에서는이 문제를 처리하는 훨씬 더 효율적인 방법이 있습니다.

  • 자바 finalize
  • C # using
  • 바둑 defer

우리는 RAII를 가지고 있으며, 그의 흥미로운 부동산은 SBRM(Scoped Bound Resources Management) 로 요약됩니다 .

소멸자가 소유 한 리소스를 정리할 수 있도록 클래스를 만들면 각 사용자마다 리소스를 관리하지 않아도됩니다!

이다 내가 다른 언어로 그리워 기능을 대부분 잊어 아마도 하나.

사실 try/catch로깅없이 종료되지 않도록 최상위 레벨을 제외하고 C ++ 로 블록을 작성할 필요가 거의 없습니다 .


1
나는 (당신은 직접 대체 할 수 그것의 C.만큼 자바의 영향을 생각하지 않습니다 fopenfclose여기에.) RAII 여기 일을 할 수있는 "적절한"방법이지만, C에서 C 라이브러리를 사용하고자하는 사람들을위한 그것의 불편 ++ .
dan04

이 유형의 답변에는 올바른 솔루션의 예를 제공하는 것이 적절할 것입니다.
Claus Jørgensen

ClausJørgensen @ : 음, 그냥 포함하기 때문에이 솔루션은 불행하게도 정말 "화려한"아니다 File file("some.txt");(NO 및 그것 뿐이다 open아니, close아니, try...)
마티유 M.

D는 또한 RAII를 가지고 있습니다
Demi

@ Demetri : 나는 D에 너무 익숙하지 않다 .RAII가 가비지 콜렉션과 어떻게 상호 작용하는지 설명 할 수 있습니까? 파이썬에서 "deinit"메소드를 작성할 수 있다는 것을 알고 있지만 문서는 참조 순환의 경우 일부 객체가 deinit 메소드가 호출되지 않는다고 경고합니다.
Matthieu M.

9

기준에 맞는 일반적인 오류 중 하나는 클래스에서 할당 된 메모리를 처리 할 때 복사 생성자가 작동하는 방식을 이해하지 못하는 것입니다. 'noob'이 객체를 맵이나 벡터에 넣고 복사 생성자와 소멸자를 올바르게 작성하지 않았기 때문에 충돌이나 메모리 누수를 수정하는 데 걸린 시간을 잃었습니다.

불행히도 C ++에는 이와 같은 '숨겨진'문제가 가득합니다. 그러나 그것에 대해 불평하는 것은 당신이 프랑스에 갔다고 불평하고 사람들의 말을 이해하지 못하는 것과 같습니다. 거기에 가려면 언어를 배우십시오.


1
C ++의 문제는 발로 자신을 쏘는 것이 매우 쉽다는 것입니다. 물론, 좋은 C ++ 프로그래머가 있고 C ++로 작성된 좋은 소프트웨어가 많이 있습니다. 그러나 좋은 C ++ 개발자가 되기는 매우 어렵습니다. Scott Meyers 'Efficient C ++'시리즈는 언어의 미묘한 정도를 보여줍니다.
Marco Mustapic

동의한다. 그러나 문제의 일부는 많은 (대부분의) C ++ 프로그래머들이 분명하지 않을 때 그들이하고있는 일을 알고 있다고 생각한다는 것입니다. "유효한 C ++"을 의미 했습니까?
Henry

적어도 이것은 C ++ 0x에서 암시 적 복사 / 이동 작업 생성에 대한 새로운 다소 제한적인 규칙으로 개선되고 있습니다. 대부분의 3 가지 위반 사례에서 암시적인 복사 작업 생성은 더 이상 사용되지 않으며 경고를 생성해야합니다.
sellibitze

6

C ++ 다양한 기능과 프로그래밍 스타일을 허용하지만 이것이 실제로 C ++을 사용하는 좋은 방법은 아닙니다. 실제로 C ++을 잘못 사용하는 것은 매우 쉽습니다.

그것은되어야 배우고 제대로 이해 inefficent 오류가 발생하기 쉬운 코드로 이어질 것입니다 단지 일을 (또는 어떤 다른 언어를 사용하는 것처럼 사용)에 의해 학습.


4

글쎄 ... 우선 C ++ FAQ Lite를 읽을 수 있습니다.

그런 다음 여러 사람들이 C ++의 복잡성에 관한 책을 쓰고 경력을 쌓았습니다.

Herb Sutter Scott Meyers 즉.

물질이 부족한 토발즈의 비난에 관해서는, 사람들을 진지하게 생각해보십시오. Python & Ruby & Java 서적은 모두 애플리케이션 작성에 중점을두고 있습니다. C ++ 서적은 어리석은 언어 기능 / 팁 / 트랩에 중점을 둡니다.


1
흠 ... javapuzzlers.com , jimbrooks.org/web/python/#Pitfalls . 내가 말하고 싶지만 ++ C를 가속 (하나의 예를 들어) 더 초점을 맞 춥니 다 이보다 쓰기 코드를 ... 어떻게에
제리 관을

1
각각의 언어로 된 사례를 지적하는 몇 가지 자료의 예를 제시했습니다. 이상한 모양과 당신이 확신 (파이썬 목록 물건은 가까이 있지만) 그들이 일하는 것 어떻게하지 않은 일이 ... C ++는 전체가 업계 것을 지적 보는 방식으로 행동은 당신이 기대하지 않는 것이 완벽하게 유효합니다.
red-dirt

3

템플릿이 너무 무거 우면 처음에는 버그가 발생하지 않을 수 있습니다. 하지만 시간이 지남에 따라 사람들은 해당 코드를 수정해야하며 거대한 템플릿을 이해하기가 어려울 것입니다. 버그가 입력 될 때입니다. 오해로 인해 "컴파일 및 실행"주석이 생겨 거의 대부분 정확한 코드가 아닙니다.

일반적으로 3 단계의 딥 제네릭 템플릿을 사용하는 것을 본다면 그 방법을 하나로 줄일 수 있다고 생각합니다. 함수 나 클래스를 추출하여 문제를 해결하는 경우가 종종 있습니다.


8
변화하는 요구 사항에 직면하여 복잡한 코드를 유지 관리 하면 많은 노력을 기울이지 않아도 항상 버그가 발생하며 템플릿에는 특별한 문제가 없습니다.
Fred Nurk

2

경고 : 이것은 "사용자가 알지 못하는"것이 그의 답변에서 연계 된 대화에 대한 비판만큼 답이 아닙니다.

그의 첫 번째 요점은 (어쩌면) "항상 변하는 표준"입니다. 실제로, 그가 제공하는 예제 는 표준이 있기 전에 C ++의 변경과 관련 이 있습니다. 1998 년 이후 (첫 번째 C ++ 표준이 완성 된 이후) 언어에 대한 변경은 매우 적었습니다. 실제로 많은 사람들은 더 많은 변경이 이루어져야 한다는 실제 문제가 있다고 주장합니다 . 원래 C ++ 표준을 따르는 모든 코드가 여전히 현재 표준을 따르는 지 확실합니다. 다소 확실 하지는 않지만 무언가가 빠르게 (그리고 예기치 않게) 변경되지 않는 한 곧 C ++ 표준 (이론적으로 사용 된 모든 코드)과 거의 동일합니다.export깨질 것이지만 실제로는 존재하지 않습니다. 실제적인 관점에서 보면 문제가되지 않습니다). 나는 그런 주장을 할 수있는 다른 언어들, OS들 (또는 컴퓨터와 관련된 다른 많은 것들)을 생각할 수있다.

그런 다음 "모든 스타일 변경"에 들어갑니다. 다시 말하지만, 그의 요점은 대부분 넌센스에 가깝습니다. 그는 for (int i=0; i<n;i++)"오래되고 파열되었다"고 for (int i(0); i!=n;++i)"새로운 뜨거움" 으로 특성화하려고한다 . 실제로 이러한 변경이 의미가있는 유형이 있지만 int차이가 없으며, 무언가를 얻을 수있는 경우에도 올바른 코드를 작성하는 데 거의 필요하지 않습니다. 아주 좋은 경우에도 그는 두더지에서 산을 만들고 있습니다.

그의 다음 주장은 C ++가 "잘못된 방향으로 최적화하고있다"는 것이다. 특히 그는 좋은 라이브러리를 사용하는 것이 쉽다는 것을 인정하지만 C ++은 "좋은 라이브러리를 작성하는 것이 거의 불가능하다"고 주장했다. 여기서 나는 그의 가장 근본적인 실수 중 하나라고 생각합니다. 실제로 거의 모든 언어에 적합한 라이브러리를 작성 하는 것은 매우 어렵습니다. 최소한 좋은 라이브러리를 작성하려면 일부 문제 도메인을 잘 이해해야 코드가 해당 도메인에서 (또는 관련) 여러 응용 프로그램에서 작동 할 수 있습니다. 대부분의 어떤 C ++ 정말 "높였"입니다 않습니다 - 라이브러리가 얼마나 더보고 후 일, 사람들이 그렇지 않은 것 dreck의 종류를 쓰기로 돌아갈 거의하고자합니다.정말 좋은 코더는 꽤 많은 라이브러리를 작성하는데, "라이브러리"에 의해 쉽게 사용될 수 있습니다. 이것은 실제로 "버그가 아니라 기능"인 경우입니다.

나는 모든 지점을 순서대로 맞추려고하지는 않지만 (페이지를 차지할 것입니다), 그의 마감 지점으로 직접 건너 뜁니다. Bjarne은 다음과 같이 말합니다. "사용하지 않는 가상 함수 테이블 및 RTTI 데이터를 제거하기 위해 전체 프로그램 최적화를 사용할 수 있습니다. 이러한 분석은 동적 링크를 사용하지 않는 비교적 작은 프로그램에 특히 적합합니다."

그는 "이것은 정말 어려운 문제" 라는 주장을지지함으로써이를 비판합니다 . 실제로 Zortech C ++에 포함 된 링커 (실제로 1980 년대에 MS-DOS를위한 최초의 C ++ 컴파일러)에 포함 된 링커 가이를 수행했습니다. 아마도 엄청난 양의 모든 데이터가 제거되었다고 확신하기는 어렵지만, 꽤 공정한 일을하는 것은 전적으로 합리적입니다.

그럼에도 불구하고, 훨씬 더 중요한 점은 이것이 대부분의 프로그래머에게는 전혀 관련이 없다는 것입니다. 라이브러리를 전혀 사용하지 않고 어셈블리 언어를 작성하지 않는 한, 상당히 많은 코드를 해체 한 우리도 알다시피, 실행 파일에는 거의 확실하게 상당한 양의 "재료"(일반적인 경우 코드와 데이터)가 포함되어 있습니다. 실제로 사용하는 것을 언급하지 않고 아마도 알지 못할 수도 있습니다. 가장 작은 임베디드 시스템을 위해 개발하지 않는 한, 추가 스토리지 소비량은 그다지 중요하지 않은 대부분의 사람들에게는 대부분 중요하지 않습니다.

결국,이 rant는 Linus의 관용보다 조금 더 많은 물질을 가지고 있다는 것이 사실입니다.


1

피할 수없는 상황으로 인해 C ++로 코딩해야하는 C 프로그래머로서 여기 내 경험이 있습니다. 내가 사용하는 C ++은 거의 없으며 대부분 C에 충실합니다. 주된 이유는 C ++을 잘 이해하지 못하기 때문입니다. C ++의 복잡한 점과 좋은 코드를 작성하는 방법을 알려주는 멘토가 없었습니다. 그리고 아주 좋은 C ++ 코드의 안내 없이는 좋은 코드를 C ++로 작성하는 것이 매우 어렵습니다. IMHO 초보자를 기꺼이 잡고 싶어하는 훌륭한 C ++ 코더가 오기 어렵 기 때문에 이것이 C ++의 가장 큰 단점입니다.

필자가 보았던 일부 성능 저하는 일반적으로 STL의 마법 메모리 할당 때문입니다 (예, 할당자를 변경할 수 있지만 C ++로 시작할 때 누가 그렇게합니까?). 벡터는 내부적으로 배열을 사용하고 추상화는 매우 효율적이기 때문에 벡터와 배열은 비슷한 성능을 제공한다는 C ++ 전문가의 주장을 듣습니다. 실제로 벡터 액세스 및 기존 값 수정의 경우 이것이 사실이라는 것을 알았습니다. 그러나 벡터의 새로운 진입, 구성 및 파괴를 추가하는 것은 사실이 아닙니다. gprof는 애플리케이션 생성 시간의 25 %가 벡터 생성자, 소멸자, memmove (새 요소를 추가하기 위해 전체 벡터를 재배치하는 데 사용됨) 및 기타 과부하 된 벡터 연산자 (++와 같은)에 소비 된 것으로 나타났습니다.

동일한 응용 프로그램에서 somethingSmall의 벡터가 somethingBig을 나타내는 데 사용되었습니다. somethingBig에있는 small에 대한 임의의 액세스가 필요하지 않았습니다. 리스트 대신 여전히 벡터가 사용되었습니다. 벡터가 사용 된 이유는 무엇입니까? 원래의 코더는 벡터 구문과 같은 배열에 익숙하고 목록에 필요한 반복자에는 익숙하지 않기 때문에 (그렇습니다. 그는 C 배경 출신입니다). 계속해서 C ++을 올바르게 얻으려면 전문가의 많은 지침이 필요하다는 것을 증명합니다. C는 추상화가 전혀없는 기본적인 구성을 거의 제공하지 않으므로 C ++보다 훨씬 쉽게 얻을 수 있습니다.



0

STL 및 부스트는 소스 코드 수준에서 이식 가능합니다. Linus가 말하는 것은 C ++에 ABI (응용 프로그램 이진 인터페이스)가 없다는 것입니다. 따라서 동일한 컴파일러 버전과 동일한 스위치를 사용하여 연결하는 모든 라이브러리를 컴파일하거나 dll 경계의 C ABI로 제한해야합니다. 또한 그 애너 링을 발견합니다. 그러나 타사 라이브러리를 만들지 않는 한 빌드 환경을 제어 할 수 있어야합니다. 나는 C ABI로 자신을 제한하는 것은 문제가되지 않습니다. 한 dll에서 다른 dll로 문자열, 벡터 및 스마트 포인터를 전달할 수 있다는 편의는 컴파일러를 업그레이드하거나 컴파일러 스위치를 변경할 때 모든 라이브러리를 다시 작성해야하는 문제가 있습니다. 내가 따르는 황금률은 다음과 같습니다.

구현이 아닌 인터페이스를 재사용하도록 상속

상속보다 집계 선호

-멤버 메소드에 가능한 무료 기능을 선호

-항상 RAII 관용구를 사용하여 코드를 매우 안전하게 보호하십시오. 잡으려고하지 마십시오.

-스마트 포인터를 사용하고, 알몸 (비 유지) 포인터를 피하십시오

-의미 체계를 참조하기 위해 값 의미 체계를 선호

-바퀴를 재발 명하지 말고 STL과 부스트를 사용하십시오.

-Pimpl 관용구를 사용하여 개인을 숨기거나 컴파일러 방화벽을 제공하십시오.


-6

;적어도 일부 버전의 VC에서는 clase 선언의 끝에 결말을 넣지 않습니다 .


4
이것은 초보자에게 매우 흔한 실수 일 것입니다 (아직도 여전히 기본적인 문법을 배우는 사람에게는 거의 모든 것이 있습니다). 그러나 스스로 유능하다고 부르고 여전히이 실수를 주목할만한 사람들이 많이 있습니까?
Fred Nurk

1
컴파일러가 세미콜론 부족과 관련이없는 오류를 줬기 때문에 그것을 썼습니다.
Marco Mustapic

2
예, 정확히 동일한 오류는 C 컴파일러에서 얻는 것입니다.
Mircea Chirea
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.