함수 오버로드에만 C ++ 컴파일러를 사용하는 것은 나쁜 습관입니까?
IMHO의 견해, 예, 두 언어를 모두 좋아하기 때문에이 언어에 대답하려면 정신 분열증이되어야하지만, 효율성과는 관련이 없지만 언어의 안전과 관용적 표현과 비슷합니다.
C면
C 관점에서 함수 오버로드를 사용하기 위해 코드에 C ++이 필요하면 낭비가됩니다. C ++ 템플릿을 사용하여 정적 다형성에 사용하지 않는 한 완전히 다른 언어로 전환하는 대신 얻는 사소한 구문 설탕입니다. 또한 함수를 dylib로 내보내려면 (실제로 우려 할 수도 있고 아닐 수도 있음) 더 이상 모든 이름이 얽힌 기호를 사용하여 광범위하게 소비하기 위해 그렇게 할 수 없습니다.
C ++ 사이드
C ++ 관점에서 함수 오버로드와 함께 C와 같은 C ++을 사용해서는 안됩니다. 이것은 문체적인 독단성이 아니라 일상적인 C ++의 실제적인 사용과 관련된 것입니다.
C 유형의 시스템에 대해 작업하는 경우 C 유형의 시스템에 대해 작업하는 경우 일반적인 C 코드 코드는 합리적으로 제정되고 "안전"합니다 structs
. C ++의 훨씬 더 풍부한 유형의 시스템에서 작업하고 나면 매일 가치가 memset
있고 memcpy
기능이되지 않는 일일 함수는 항상 기대어야합니다. 대신 C ++ 유형의 경우 복사 및 셔플 링 및 해제 할 원시 비트 및 바이트처럼 처리해서는 안되기 때문에 일반적으로 전염병처럼 피하고 싶은 함수입니다. 현재 코드 memset
에서 프리미티브 및 POD UDT와 같은 것을 사용하더라도 누군가가 사용하는 UDT에 ctor를 추가하는 순간 (예 : 하나를 필요로하는 멤버 추가 만 포함)std::unique_ptr
이러한 함수 또는 가상 함수 또는 이러한 종류의 항목에 대해 정의하면 모든 일반적인 C 스타일 코딩이 정의되지 않은 동작에 취약 해집니다. Herb Sutter 자신에게서 가져옵니다.
memcpy
및 memcmp
타입 시스템을 위반. 사용하여 memcpy
객체를 복사하는 복사기를 사용하여 돈을 버는 것과 같다. 사용하여 memcmp
객체를 비교하는 것은 자신의 명소를 계산하여 표범을 비교하는 것과 같다. 도구와 방법이 작업을 수행하는 것처럼 보일 수 있지만 너무 거칠어 수용 할 수 없습니다. C ++ 객체는 정보 숨기기에 관한 것입니다 (소프트웨어 엔지니어링에서 가장 수익성 높은 원칙; 항목 11 참조). 객체는 데이터를 숨기고 (항목 41 참조) 생성자와 할당 연산자를 통해 데이터를 복사하기위한 정확한 추상화를 고안합니다 (항목 52 ~ 55 참조) . 이를 통해 모든 것을 극복하는 것은 memcpy
정보 숨기기를 심각하게 위반하는 것이며, 종종 메모리 및 리소스 누수 (최고), 충돌 (최악) 또는 정의되지 않은 동작 (최악)-C ++ 코딩 표준으로 이어집니다.
철학 은 C ++로 코드를 작성하는 경우 에만 적용 되므로 많은 C 개발자가 이에 동의하지 않고 올바르게 동의 합니다. C ++로 빌드되는 코드에서 항상 같은 함수를 사용하면 문제가 많은 코드를 작성하고 있을 가능성 이 높지만 C 에서 수행하면 문제가 없습니다 . 두 가지 언어는 유형 시스템의 차이로 인해 이와 관련하여 매우 다릅니다. 이 두 기능이 공통적으로 갖는 기능의 하위 집합을보고 싶은 유혹이 있으며 특히 C ++ 측면에서 다른 것과 같이 사용할 수 있다고 생각하지만 C + 코드 (또는 C-- 코드)는 일반적으로 C와 C보다 훨씬 더 문제가 많습니다. C ++ 코드.memcpy
마찬가지로 malloc
C 스타일 컨텍스트 (EH를 의미하지 않음)에서 던질 수있는 C ++ 함수를 직접 호출 할 수 있다면 사용해서는 안됩니다. free
메모리에 접근 하기 전에 C 스타일 코드 작성을 효과적으로 잡을 수없는 예외 . 당신이와 C로 ++ 빌드 파일있을 때마다 그래서 .cpp
확장 또는 무엇이든을하고 같은 것들의 모든 유형을한다 malloc
, memcpy
, memset
,qsort
등으로, 기본 유형에서만 작동하는 클래스의 구현 세부 정보가 아닌 한, 아직 안전하지 않은 경우 예외 처리를 수행 해야하는 경우가 아니라면 아직 문제를 묻고 있습니다. 당신은 C ++ 코드를 작성하는 경우 대신 일반적으로 RAII에 의존와 같은 것들을 사용하려면 vector
, unique_ptr
, shared_ptr
, 등, 그리고 가능하면 모든 일반 C 스타일의 코딩을 피하십시오.
C 및 x-ray 데이터 유형의 면도날을 사용하여 팀에서 부수적 피해를 입히지 않고 비트 및 바이트로 재생할 수있는 이유는 여전히 어떤 방법 으로든 자신을 해칠 수 있기 때문입니다. 유형 은 할 수 있지만 결코 할 수없는 일 때문에. 예외 처리와 함께 ctors, dtors 및 vtables와 같은 C ++ 기능을 포함하도록 C 유형 시스템을 확장하는 순간 모든 관용적 C 코드가 현재보다 훨씬 더 위험하게 렌더링되며 새로운 종류의 코드가 표시됩니다. C ++에서 볼 수 있듯이 완전히 다른 스타일의 코딩을 장려하는 철학과 사고 방식. 이제 RAII 준수 리소스와 달리 메모리를 관리하는 클래스에 대해 원시 포인터 과실을 사용하는 것을 고려합니다 unique_ptr
. 그 사고 방식은 절대적인 안전 감각에서 벗어나지 않았습니다. 유형 시스템을 통해 허용 되는 것만으로 예외 처리와 같은 기능에 대해 C ++이 특히 안전 해야하는 것에서 진화했습니다 .
예외 안전
다시 말하지만, 당신이 C ++ 땅에있는 순간, 사람들은 여러분의 코드가 예외 안전하다고 기대할 것입니다. 사람들은 미래에 코드를 이미 C ++로 작성 및 컴파일 std::vector, dynamic_cast, unique_ptr, shared_ptr
하고 코드에서 직접 또는 간접적으로 호출 된 코드에서 간단히 코드 를 사용 하여 코드가 이미 "추정 적으로"C ++이기 때문에 무해하지 않다고 생각할 때 코드를 유지 관리 할 수 있습니다. 암호. 그 시점에서 우리는 일이 발생할 가능성에 직면해야하며, 다음과 같이 완벽하고 훌륭하고 멋진 C 코드를 취할 때 :
int some_func(int n, ...)
{
int* x = calloc(n, sizeof(int));
if (x)
{
f(n, x); // some function which, now being a C++ function, may
// throw today or in the future.
...
free(x);
return success;
}
return fail;
}
... 이제 고장났습니다. 예외 안전을 위해 다시 작성해야합니다.
int some_func(int n, ...)
{
int* x = calloc(n, sizeof(int));
if (x)
{
try
{
f(n, x); // some function which, now being a C++ function, may
// throw today or in the future (maybe someone used
// std::vector inside of it).
}
catch (...)
{
free(x);
throw;
}
...
free(x);
return success;
}
return fail;
}
심한! 그렇기 때문에 대부분의 C ++ 개발자는 이것을 대신 요구합니다.
void some_func(int n, ...)
{
vector<int> x(n);
f(x); // some function which, now being a C++ function, may throw today
// or in the future.
}
위의 코드는 C ++ 개발자가 일반적으로 승인하는 RAII 준수 예외 안전 코드입니다 throw
.
언어를 선택하십시오
RAII, 예외 안전, 템플릿, OOP 등을 사용하여 C ++의 유형 시스템과 철학을 채택하거나 원시 비트와 바이트를 중심으로 크게 변화하는 C를 채택해야합니다. 이 두 언어 사이에서 거룩하지 않은 결혼 관계를 형성해서는 안되며, 두 언어를 모호하게 만드는 대신 서로 다른 언어로 분리하여 다르게 취급해야합니다.
이 언어들은 당신과 결혼하기를 원합니다. 당신은 일반적으로 둘 다 데이트하고 장난하는 대신 하나를 선택해야합니다. 또는 당신은 나와 같은 일부 다처 주의자가되고 둘 다 결혼 할 수 있지만, 서로 시간을 보낼 때 생각을 완전히 바꾸고 서로 싸우지 않도록 서로 분리해야합니다.
이진 크기
호기심 때문에 방금 무료 목록 구현 및 벤치 마크를 취해 이것에 대해 궁금해 한 이후 C ++로 포팅하려고했습니다.
[...] C 컴파일러를 사용하지 않았기 때문에 C의 모양을 모릅니다.
... 이진 크기가 C ++로 빌드하는 것만으로 팽창하는지 알고 싶었습니다. 나는 어리석은 곳에서 명시 적 캐스트를 뿌려야했습니다 (C에서 할당 자 및 데이터 구조와 같은 저수준 항목을 실제로 작성하는 것을 좋아하는 이유 중 하나).
, C로를 구축하고 말 사용과 단지 차이 - 이것은 단순한 콘솔 응용 프로그램과 ++ 기능, 심지어 연산자 오버로딩을 어떤 C를 사용하지 않은 코드와 함께 MSVC 64 비트 릴리스 빌드를 비교 한 <cstdlib>
대신 <stdlib.h>
과 그런 것들이지만 바이너리 크기와 전혀 차이가 없다는 사실에 놀랐습니다!
바이너리는 9,728
C로 빌드 9,278
될 때 바이트 였으며 마찬가지로 C ++ 코드로 컴파일 될 때 바이트였습니다. 나는 실제로 그것을 기대하지 않았다. 나는 EH와 같은 것들이 적어도 거기에 조금 더 추가 될 것이라고 생각했지만 (적어도 100 바이트와 다를 것이라고 생각했지만) 아마도 내가 EH 관련 지침을 추가 할 필요가 없다는 것을 알 수 있었을 것입니다. C 표준 라이브러리를 사용하면 아무것도 던지지 않습니다. 나는 무언가를 생각 했다RTTI와 같이 이진 크기에 약간을 추가합니다. 여하튼, 그것을 보는 것은 약간 시원했다. 물론이 결과에서 일반화해야한다고 생각하지는 않지만 적어도 나에게 깊은 인상을주었습니다. 또한 벤치 마크에 영향을 미치지 않았으며 결과적으로 동일한 결과 바이너리 크기도 동일한 결과 기계 명령을 의미한다고 생각하기 때문에 자연스럽게 그렇게합니다.
즉, 위에서 언급 한 안전 및 엔지니어링 문제로 이진 크기를 걱정하는 사람은 누구입니까? 다시 한 번 말하지만, 언어를 선택하지 말고 철학을 받아들이십시오. 그것이 제가 추천하는 것입니다.
//
의견 을 가질 수 있도록 C 기능 만 사용하는 프로젝트에 C ++을 사용하는 것으로 알려져 있습니다 . 작동한다면 왜 안 되겠습니까?