문제

는 누구나 여기서 사용하는 C++'s"새로운 배치"?그렇다면,그리고 그 이유는 무엇입니까?그것은 나에게 보이 그것을 좋아하는 것만 유용한 메모리에 매핑된 하드웨어입니다.

도움이 되었습니까?

해결책

배치 새로 사용하면 이미 할당 된 메모리에 객체를 구성 할 수 있습니다.

객체의 여러 인스턴스를 구성해야 할 때 최적화를 위해이 작업을 수행 할 수 있으며 새 인스턴스가 필요할 때마다 메모리를 다시 할 수없는 것이 더 빠릅니다. 대신, 한 번에 모든 객체를 사용하고 싶지 않더라도 여러 객체를 보유 할 수있는 메모리 덩어리에 대해 단일 할당을 수행하는 것이 더 효율적일 수 있습니다.

Devx는 a 좋은 예:

Standard C ++는 또한 배치 새 연산자를 지원하여 사전 배치 된 버퍼에 객체를 구성합니다. 이것은 메모리 풀, 쓰레기 수집가 또는 단순히 성능 및 예외 안전이 가장 중요 할 때 유용합니다 (메모리가 이미 할당되었으므로 할당 실패의 위험이 없으며 사전에 할당 된 버퍼에 객체를 구성하는 데 시간이 걸리지 않습니다). :

char *buf  = new char[sizeof(string)]; // pre-allocated buffer
string *p = new (buf) string("hi");    // placement new
string *q = new string("hi");          // ordinary heap allocation

중요 코드의 특정 부분 (예 : 맥박 조정기가 실행 된 코드)에서 할당 실패가 없을 수도 있습니다. 이 경우 메모리를 일찍 할당 한 다음 중요한 섹션 내에서 새로 배치하는 것을 사용하려고합니다.

배치의 거래는 새로운 것입니다

메모리 버퍼를 사용하는 모든 객체를 처리해서는 안됩니다. 대신 원래 버퍼 만 삭제해야합니다. 그런 다음 수업의 소멸자에게 수동으로 전화해야합니다. 이에 대한 좋은 제안은 Stroustrup의 FAQ를 참조하십시오. "배치 삭제"가 있습니까??

다른 팁

사용자 정의 메모리 풀과 함께 사용합니다. 그냥 스케치 :

class Pool {
public:
    Pool() { /* implementation details irrelevant */ };
    virtual ~Pool() { /* ditto */ };

    virtual void *allocate(size_t);
    virtual void deallocate(void *);

    static Pool::misc_pool() { return misc_pool_p; /* global MiscPool for general use */ }
};

class ClusterPool : public Pool { /* ... */ };
class FastPool : public Pool { /* ... */ };
class MapPool : public Pool { /* ... */ };
class MiscPool : public Pool { /* ... */ };

// elsewhere...

void *pnew_new(size_t size)
{
   return Pool::misc_pool()->allocate(size);
}

void *pnew_new(size_t size, Pool *pool_p)
{
   if (!pool_p) {
      return Pool::misc_pool()->allocate(size);
   }
   else {
      return pool_p->allocate(size);
   }
}

void pnew_delete(void *p)
{
   Pool *hp = Pool::find_pool(p);
   // note: if p == 0, then Pool::find_pool(p) will return 0.
   if (hp) {
      hp->deallocate(p);
   }
}

// elsewhere...

class Obj {
public:
   // misc ctors, dtors, etc.

   // just a sampling of new/del operators
   void *operator new(size_t s)             { return pnew_new(s); }
   void *operator new(size_t s, Pool *hp)   { return pnew_new(s, hp); }
   void operator delete(void *dp)           { pnew_delete(dp); }
   void operator delete(void *dp, Pool*)    { pnew_delete(dp); }

   void *operator new[](size_t s)           { return pnew_new(s); }
   void *operator new[](size_t s, Pool* hp) { return pnew_new(s, hp); }
   void operator delete[](void *dp)         { pnew_delete(dp); }
   void operator delete[](void *dp, Pool*)  { pnew_delete(dp); }
};

// elsewhere...

ClusterPool *cp = new ClusterPool(arg1, arg2, ...);

Obj *new_obj = new (cp) Obj(arg_a, arg_b, ...);

이제 단일 메모리 경기장에서 객체를 함께 클러스터링하고, 매우 빠르지 만 할당이있는 할당자를 선택할 수 있지만, 메모리 매핑을 사용하고, 수영장을 선택하고 객체의 배치에 인수로 전달하여 부과하고자하는 다른 의미 론적 인 모든 의미 론적. 새로운 운영자.

할당을 초기화와 분리하려는 경우 유용합니다. STL은 컨테이너 요소를 생성하기 위해 새로운 배치를 사용합니다.

실시간 프로그래밍에 사용했습니다. 우리는 일반적으로 ~하지 않다 시스템이 시작된 후 동적 할당 (또는 거래)을 수행하려고합니다. 왜냐하면 얼마나 오래 걸릴지 보장 할 수 없기 때문입니다.

내가 할 수있는 것은 큰 기억 덩어리를 Prealloce입니다 (수업이 요구할 수있는 모든 양을 유지하기에 충분히). 그런 다음 런타임에 물건을 구성하는 방법을 알아 내면 새 배치를 사용하여 원하는 곳에 바로 객체를 구성 할 수 있습니다. 내가 그것을 사용했던 한 가지 상황은 이기종을 만드는 데 도움이되었습니다. 원형 버퍼.

확실히 희미한 마음을위한 것은 아니지만, 그들이 끔찍한 구문을 만드는 이유입니다.

Alloca ()를 통해 스택에 할당 된 물체를 구성하는 데 사용했습니다.

뻔뻔한 플러그 : 나는 그것에 대해 블로그를 작성했다 여기.

헤드 괴짜 : 빙고! 당신은 그것을 완전히 얻었습니다 - 그것은 정확히 완벽한 것입니다. 많은 임베디드 환경에서 외부 제약 및/또는 전반적인 사용 시나리오는 프로그래머가 객체의 할당을 초기화와 분리하도록 강요합니다. C ++는 함께 묶여서 이것을 "인스턴스화"라고 부릅니다. 그러나 생성자의 동작이 동적 또는 자동 할당없이 명시 적으로 호출되어야 할 때마다 새로운 배치는이를 수행하는 방법입니다. 또한 하드웨어 구성 요소 (메모리 매핑 된 I/O)의 주소에 고정 된 전역 C ++ 객체를 찾거나 어떤 이유로 든 고정 된 주소로 거주 해야하는 정적 객체에 대해 완벽한 방법입니다.

변형 클래스를 만드는 데 사용했습니다 (즉, 여러 가지 다른 유형 중 하나 일 수있는 단일 값을 나타낼 수있는 객체).

변형 클래스에서 지원하는 모든 값 유형이 POD 유형 (예 : int, float, double, bool) 인 경우 태그가 붙은 C 스타일 Union이 충분하지만 값 유형 중 일부가 C ++ 객체가되기를 원한다면 ( 예를 들어 std :: string), C Union 기능은 비 POD 데이터 유형이 노조의 일부로 선언되지 않을 수 있으므로 수행되지 않습니다.

대신 나는 충분히 큰 바이트 배열을 할당하고 (예 : sizeof (the_largest_data_type_i_support))를 사용하여 해당 유형의 값을 유지하도록 설정된 경우 해당 영역에서 적절한 C ++ 객체를 초기화하기 위해 새로운 배치를 사용합니다. (및 다른 비 POD 데이터 유형에서 멀어 질 때 미리 배치 삭제)

그것은 또한 유용하고 싶을 때는 다시 초기화 글로벌 또는 정적으로 할당된 구조물입니다.

오 C 방법을 사용하여 memset() 을 설정하는 모든 요소들은 0 입니다.당신은 할 수 없는 C++에서 인 vtables 및 사용자 정의 개체 생성자입니다.

그래서 가끔 다음 사용

 static Mystruct m;

 for(...)  {
     // re-initialize the structure. Note the use of placement new
     // and the extra parenthesis after Mystruct to force initialization.
     new (&m) Mystruct();

     // do-some work that modifies m's content.
 }

커널을 빌드하는 경우 유용합니다. 디스크에서 읽은 커널 코드 또는 Pagetable에서 어디에 배치합니까? 어디로 점프 해야할지 알아야합니다.

또는 할당 된 방이 많고 서로 뒤에 몇 가지 구조물을 배치하고 싶을 때와 같은 다른 매우 드문 상황에서. 오프셋 () 연산자가 필요하지 않고도이 방식으로 포장 할 수 있습니다. 그래도 다른 트릭도 있습니다.

또한 일부 STL 구현이 std :: 벡터와 같이 새 배치를 사용한다고 생각합니다. 그들은 그런 식으로 2^n 요소를위한 공간을 할당하며 항상 재 할당 할 필요는 없습니다.

배치 새로는 직렬화 할 때 매우 유용합니다 (부스트 :: 직렬화). C ++ 10 년 동안 이것은 새로운 배치가 필요한 두 번째 사례 일뿐입니다 (세 번째 인터뷰 포함 :)).

나는 이것이 어떤 답에 의해 강조되지 않았다고 생각하지만, 또 다른 좋은 예와 사용법은 새로운 배치 메모리 파편화를 줄이는 것입니다 (메모리 풀을 사용하여). 이는 임베디드 및 고 가용성 시스템에 특히 유용합니다. 이 마지막 경우에는 24/365 일을 실행 해야하는 시스템의 경우 조각화가없는 것이 매우 중요하기 때문에 특히 중요합니다. 이 문제는 메모리 누출과 관련이 없습니다.

매우 우수한 malloc 구현이 사용 되더라도 (또는 유사한 메모리 관리 기능) 오랫동안 조각화를 다루는 것은 매우 어렵습니다. 어떤 시점에서, 당신이 영리하게 관리하지 않으면 메모리 예약/릴리스 호출을 많이 작은 간격 재사용이 어렵습니다 (새로운 예약에 할당). 따라서이 경우에 사용되는 솔루션 중 하나는 메모리 풀을 사용하여 응용 프로그램 개체의 메모리를 손에 넣는 것입니다. 나중에 일부 개체에 대한 메모리가 필요할 때마다 새로운 배치 이미 예약 된 메모리에 새 개체를 만듭니다.

이런 식으로 응용 프로그램이 시작되면 이미 필요한 모든 메모리가 예약되어 있습니다. 모든 새로운 메모리 예약/릴리스는 할당 된 풀로 이동합니다 (각 객체 클래스마다 하나씩 여러 풀이있을 수 있음). 이 경우에는 간격이없고 단편화로 고통받지 않고도 매우 오랜 기간 동안 (년)를 실행할 수 있기 때문에이 경우 메모리 조각화가 발생하지 않습니다.

기본 메모리 할당 시스템이 조각화로 인해 많은 어려움을 겪기 때문에 VXWorks RTO에 대해 특별히 이것을 보았습니다. 따라서 표준 새/malloc 방법을 통해 메모리를 할당하는 것은 기본적으로 프로젝트에서 금지되었습니다. 모든 메모리 예약은 전용 메모리 풀로 이동해야합니다.

나는 그것을 사용에 대한 개체를 저장하고 있으로 메모리에 매핑된 파일이 있습니다.
특정 예었던 이미지 데이터베이스는 처리 참 큰 숫자의 큰 이미지(보다 더 많은 수 있는 메모리에 맞).

나는 그것이 사용되는 것을 보았다 "동적 유형"포인터에 대한 약간의 성능 해킹 ( "후드 아래"섹션에서) :

그러나 여기에 작은 유형에 대한 빠른 성능을 얻는 데 사용한 까다로운 트릭이 있습니다. 보유하고있는 값이 공허 안에 들어갈 수 있다면*실제로 새 개체를 할당하는 것을 귀찮게하지 않습니다. .

사용합니다 std::vector<> 왜냐하면 std::vector<> 일반적으로 그보다 더 많은 메모리를 할당합니다 objects 에서 vector<>.

그것의 실제 종류의 구현하는 데 필요한 모든 종류의 데이터 구조를 할당하는 것보다 더 많은 메모리는 최소한의 수에 필요한 요소를 삽입된다(즉,아무것도 아닌 다른 연결된 구조는 할당 노드에서 시간).

을 같은 컨테이너 unordered_map, vector, 나 deque.이러한 모든 할당보다 더 많은 메모리는 최소한 필요한 요소를 삽입했고 지금까지할 필요가 없도록 힙 할당을 위해 모든 단일 삽입합니다.자 사용 vector 으로 가장 간단한 예제입니다.

수행할 때:

vector<Foo> vec;

// Allocate memory for a thousand Foos:
vec.reserve(1000);

...하지 않는 실제로 건설 천 Foos.그것은 단순히 할당/보유 메모리에 대한니다.는 경우 vector 를 사용하지 않았 배치기,그것은 것 기본으로 건설 Foos 모든 장소뿐만 아니라 가을 호출하는 그들의 소멸자 요소에 대해서도 당신은 심지어에 삽입되는 첫 번째 장소입니다.

배분!= 건설 자유롭게,!= 파괴

그냥 일반적으로 구현하는 많은 데이터 구조를 위와 같이,취급할 수 없을 할당하는 메모리하고 건설하는 요소 중 하나로 분할 것,그리고 당신은 마찬가지로 치료 수 없습니다 메모리를 해제하고 파괴하는 요소 중 하나로 나눌 수 없는 것입니다.

거기에 간 이러한 아이디어를 피하 superfluously 를 호출하여 생성자 및 소멸자는 불필요하게 왼쪽과 오른쪽,그 이유는 표준 라이브러리 구분의 아이디어 std::allocator (지 않는 구성하거나 파괴하는 요소를 할당/메모리를 해제*)멀리에서 용기는 사용하는 수동으로 구성 요소를 사용하여 새로운 배치 및 수동으로 파괴하는 요소를 사용하여 명시적으 호출의 소멸자입니다.

  • 나의 디자인 std::allocator 하지만 그것은 다른 주제는 내가 피해에 대해 불평.:-D

그래서 어쨌든,나는 그것을 사용하는 경향이 많은 이의 번호를 기록하는 일반 목적은 표준을 준수하는 C++컨테이너지 못한 건축의 관점에서 기존.포함된 그들 가운데는 작은 벡터로 구현 기 몇 수십 년 동안 전 힙 할당을 피하는 일반적인 경우에,메모리 효율적인 기술을 사용하여(지 않는 할당 노드에서 시간).두 경우 모두지 못했을 구현을 사용하여 그들의 기존 컨테이너,그리고 그렇게 했 사용 placement new 을 방지하 superfluously 를 호출하여 생성자 및 소멸자에 불필요한 것들을 왼쪽과 오른쪽.

자연스럽게 만약 당신이 이제까지 일으로 사용자 정의 할당자를 할당 개체는 개별적으로,무료 목록,당신은 또한 일반적으로 사용하고 싶 placement new, 이것처럼(기본적인 예는 귀찮게 하지 않으로 예외 안전 또는 RAII):

Foo* foo = new(free_list.allocate()) Foo(...);
...
foo->~Foo();
free_list.free(foo);

네트워크에서받은 메시지가 포함 된 메모리를 기반으로 객체를 만드는 데 사용했습니다.

일반적으로, 새는 새로운 배치는 '정상적인 새'의 할당 비용을 제거하는 데 사용됩니다.

내가 사용한 또 다른 시나리오는 내가 액세스하고 싶은 곳입니다. 바늘 문서 별 싱글 톤을 구현하기 위해 여전히 구성되어야 할 객체에.

내가 그것을 가로 질러 달리는 곳은 컨테이너에 있으며, 인접한 버퍼를 할당 한 다음 필요에 따라 물체로 채우는 컨테이너입니다. 언급했듯이 STD :: Vector는이 작업을 수행 할 수 있으며, 일부 버전의 MFC Carray 및/또는 Clist 가이 작업을 수행했음을 알고 있습니다. 버퍼 과도 할당 방법은 매우 유용한 최적화이며, 새 배치는 해당 시나리오에서 객체를 구성하는 유일한 방법입니다. 또한 직접 코드 외부에 할당 된 메모리 블록에 객체를 구성하는 데 때때로 사용됩니다.

자주 나타나지는 않지만 비슷한 용량으로 사용했습니다. 그러나 C ++ 도구 상자에 유용한 도구입니다.

스크립트 엔진은 기본 인터페이스에서이를 사용하여 스크립트에서 기본 객체를 할당 할 수 있습니다. 예는 Angelscript (www.angelcode.com/angelscript)를 참조하십시오.

XLL 프로젝트의 FP.H 파일을 참조하십시오 http://xll.codeplex.com 그것은 차원을 가지고 다니는 배열에 대한 "컴파일러와의 부적절한 멍청함"문제를 해결합니다.

typedef struct _FP
{
    unsigned short int rows;
    unsigned short int columns;
    double array[1];        /* Actually, array[rows][columns] */
} FP;

다음은 C ++ 내 위치 생성자에 대한 킬러 사용입니다. 캐시 라인에 정렬 및 2 개의 경계의 다른 힘. 여기에 있습니다 5 개 이하의 단일 사이클 지침으로 2 개의 경계의 모든 출력에 대한 초고속 포인터 정렬 알고리즘:

/* Quickly aligns the given pointer to a power of two boundary IN BYTES.
@return An aligned pointer of typename T.
@brief Algorithm is a 2's compliment trick that works by masking off
the desired number in 2's compliment and adding them to the
pointer.
@param pointer The pointer to align.
@param boundary_byte_count The boundary byte count that must be an even
power of 2.
@warning Function does not check if the boundary is a power of 2! */
template <typename T = char>
inline T* AlignUp(void* pointer, uintptr_t boundary_byte_count) {
  uintptr_t value = reinterpret_cast<uintptr_t>(pointer);
  value += (((~value) + 1) & (boundary_byte_count - 1));
  return reinterpret_cast<T*>(value);
}

struct Foo { Foo () {} };
char buffer[sizeof (Foo) + 64];
Foo* foo = new (AlignUp<Foo> (buffer, 64)) Foo ();

이제 그것은 단지 당신의 얼굴에 미소를 두지 않습니다 (:-). I ♥♥♥ C ++ 1X

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top