‘신규 게재 위치’에는 어떤 용도가 있습니까? 사람이 있습니까? 그렇다면

여기에 C ++의 “배치 새”를 사용한 사람이 있습니까? 그렇다면 무엇을 위해? 메모리 매핑 하드웨어에서만 유용 할 것 같습니다.



답변

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

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

DevX는 좋은 예입니다 .

표준 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은 새로운 배치를 사용하여 컨테이너 요소를 만듭니다.


답변

실시간 프로그래밍에 사용했습니다. 일반적으로 시스템 시작 후 동적 할당 (또는 할당 해제)을 수행하고 싶지 않습니다. 시간이 얼마나 걸리는지 보장 할 수 없기 때문입니다.

내가 할 수있는 일은 큰 메모리 덩어리를 미리 할당하는 것입니다 (클래스에 필요한 모든 것을 담을 수있을만큼 큼). 그런 다음 런타임에 물건을 구성하는 방법을 알아 낸 후에는 새로운 위치를 사용하여 원하는 곳에 객체를 구성 할 수 있습니다. 내가 사용했던 한 가지 상황은 이기종 순환 버퍼를 만드는 데 도움이되었다는 것입니다 .

그것은 분명 희미한 마음을위한 것이 아니지만, 그에 대한 구문을 좀 나쁘게 만드는 이유입니다.


답변

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

뻔뻔한 플러그 : 나는 그것에 대해 블로그 여기 .


답변

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


답변

Variant 클래스 (예 : 여러 유형 중 하나 일 수있는 단일 값을 나타낼 수있는 객체)를 만드는 데 사용했습니다.

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

따라서 대신 Variant가 해당 유형의 값을 보유하도록 설정된 경우 충분히 큰 바이트 배열 (예 : sizeof (the_largest_data_type_I_support))을 할당하고 new를 사용하여 해당 영역에서 적절한 C ++ 객체를 초기화합니다. (물론 다른 비 POD 데이터 유형에서 전환 할 때 배치를 미리 삭제하십시오)