2017-01-02 13 views
5

일반적으로 동적 할당이 허용되지 않고 예외가 허용되지 않는 안전 소프트웨어를 고려하십시오. 동적 할당은 클래스 explicity가 연산자 newdelete을 정의 할 때만 허용됩니다. 연산자 new을 다른 클래스에 사용하면 컴파일 오류가 발생합니다. 한편 표준 라이브러리이 원인 부작용을글로벌 운영자가없는 베어 메탈 new

void* operator new(std::size_t) = delete; 

:

이러한 상황에서 컴파일 오류가 발생할 수있는 가장 간단한 방법은 글로벌 new 연산자를 제거하는 것입니다. 예를 들어 <array>을 포함하면 <new_allocator>에 포함이 전파됩니다 (<stdexcept>). <new_allocator>::new 연산자를 사용하므로 예외 및 메모리 할당을 사용하지 않으려는 경우에도 빌드가 실패합니다. Scoot Meyers에 따르면 <array>은 베어 메탈이어야합니다. 컴파일러

한편

이 원인 오류가 내장 연산자

src/main.cpp:91:31: error: deleted definition of 'void* operator new(std::size_t)' 
void* operator new(std::size_t) = delete;        ^
<built-in>: note: previous declaration of 'void* operator new(std::size_t)' 

::new을 금지하고 <array>를 사용하는 모든 솔루션이 있습니까?

::new을 전체적으로 금지 할 해결책이 있습니까 전혀입니까? 에 관계없이 당신이 사용하는 어떤 프로그래밍 언어의

+0

링크 시간에 조금 후에 오류가 발생합니까? –

+0

@Marc 빌드에 전혀 실패한 솔루션을 사용해도 좋습니다. –

+1

가끔은 C에 대한 좋은 이유가 있습니다. 이것은 그들 중 하나처럼 들립니다. C는 숨겨진 오버 헤드를 생성하지 않습니다. '새'만이 유일한 문제는 아니지만 불신감으로 인해 문제가 발생할 수도 있습니다. 인터럽트 처리기 및 기타 시간이 중요한 경로. – Olaf

답변

4

GCC와 GNU LD를 사용하는 경우에는 --wrap=malloc을 링커 플래그에 추가하면됩니다. 외부 ::new은 내부적으로 malloc()을 사용하므로 애플리케이션에서 malloc()에 대한 모든 통화는 __wrap_malloc()으로 바뀝니다. 이 함수가 정의되지 않은 경우 연결이 실패합니다.

또 다른 가능한 옵션은 ASSERT(DEFINED(malloc) == 0, "Dynamic allocation used!");을 링커 스크립트에 추가하는 것입니다. 그러면 malloc()이 정의되어 있지 않습니다.

이 두 옵션 중 어느 것도 다른 형태의 전역 할당을 사용하기 위해 글로벌 ::new을 다시 정의 할 수 없습니다. 두 가지 내가 강조하고 싶은 있습니다

3

는 :

소리, 베어 메탈 시스템에서

, 당신은 단순히 완전히 링커 스크립트의 .heap 세그먼트를 제거합니다. 그러면 동적 할당에 의존하는 모든 코드가 연결되지 않습니다. 그리고 어쨌든 사용하지 않을 세그먼트에 RAM을 할당 할 필요가 없습니다.

+4

이 해결책은'new' 및/또는'malloc()'이 이러한 섹션의 존재에 의존하는 일부 플랫폼에서만 작동합니다. 많은 플랫폼에서 당신은 그 섹션을 필요로하지 않으며 newlib를 libc로 사용하는 모든 시스템은 당신 자신의'_sbrk_r()'함수를 구현하기 만하면됩니다. –

2

... 당신은 링커 스크립트의 전역 심볼 ::new에 대한 동일한 기능을 수행 할 수 있지만, 그 이름은 (여기 _Znwj에) 엉망이되고, 그래서 이것은 조금 이상한 것

  1. 예외와 관련된 헤더를 정의와 함께 포함하면 예외가 코드에 적용되지 않는 경우 신경 쓰지 않아도됩니다.
  2. 예외를 사용하지 않도록 설정하면 코드에서 사용할 수 없으므로 예외가 발생하면 컴파일이 실패합니다. 그러나 표준 라이브러리에서 예외 사용을 제거하지는 않습니다. 표준 라이브러리에는 std::string (예 : std::basic_string<char, ...>) 또는 std::streambuf (예 : std::basic_streambuf<char, ...>)과 같은 미리 컴파일 된 버전의 템플릿 클래스가 포함될 수 있으며 코드에서 사용할 때 컴파일러는 템플릿을 인스턴스화하지 않고 재사용합니다 예외가있는 사전 컴파일 된 버전

코드를 훨씬 잘 제어하려면 G ++ 컴파일러에서 -nostdlib 컴파일 옵션을 사용하여 표준 라이브러리를 모두 제외하는 것이 좋습니다. STL의 std::array과 같은 다양한 템플릿 클래스를 사용하는 것을 막을 수는 없지만 전체 C++ 라이브러리와 런타임은 제외됩니다.

또한 Practical Guide to Bare Metal C++을 읽는 것이 좋습니다. 그것은 C++ 베어 메탈 내부에 대한 좀 더 깊은 통찰력을 줄 것입니다.

+1

BTW - 정확히 nr 2 때문에 ARM 마이크로 컨트롤러 용으로 자체 툴킷을 컴파일했습니다. C++ 예외가 전체 libstdC++에서 제대로 비활성화되어 있습니다. - https://github.com/FreddieChopin/bleeding-edge-toolchain –