shared_ptr의 삭제 기는 커스텀 할당자가 할당 한 메모리에 저장되어 있습니까? 삭제 프로그램을

shared_ptr사용자 지정 할당 자 사용자 지정 삭제 기가 있다고 가정 해보십시오.

표준에서 삭제 프로그램을 저장할 위치에 대한 내용을 찾을 수 없습니다. 사용자 지정 할당자가 삭제 프로그램의 메모리에 사용될 것이라고 말하지 않으며 그렇지 않을 것이라고 말하지 않습니다 .

이것이 지정되지 않았습니까? 아니면 뭔가 빠졌습니까?



답변

C ++ 11의 util.smartptr.shared.const / 9 :

효과 : 객체 p와 삭제 기 d를 소유 한 shared_ptr 객체를 구성합니다. 두 번째와 네 번째 생성자는 내부 용으로 메모리를 할당하기 위해 a의 사본을 사용해야합니다.

두 번째와 네 번째 생성자에는 다음과 같은 프로토 타입이 있습니다.

template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template<class D, class A> shared_ptr(nullptr_t p, D d, A a);

최신 초안에서 util.smartptr.shared.const / 10은 다음과 같은 목적으로 사용됩니다.

효과 : 객체 p와 삭제 기 d를 소유 한 shared_ptr 객체를 구성합니다. T가 배열 유형이 아닌 경우 첫 번째 및 두 번째 생성자는 p와 shared_from_this를 활성화합니다. 두 번째와 네 번째 생성자는 내부 용으로 메모리를 할당하기 위해 a의 사본을 사용해야합니다. 예외가 발생하면 d (p)가 호출됩니다.

따라서 할당 된 메모리에 할당해야 할 경우 할당자가 사용됩니다. 현재 표준 및 관련 결함 보고서를 기반으로, 할당은 필수가 아니라위원회가 가정합니다.

  • 의 인터페이스가 있지만 shared_ptr결코 제어 블록 및 모든 없습니다 구현 할 수 shared_ptrweak_ptr링크 된 목록에 넣어가, 실제로 이러한 구현은 없다. 또한, 예를 들어, 문구 use_count가 공유 되는 것으로 가정하여 문구가 수정되었습니다 .

  • 삭제자는 구성 가능한 이동 만 필요합니다. 따라서에 여러 사본을 보유 할 수 없습니다 shared_ptr.

삭제 기를 특수하게 설계 shared_ptr하여 shared_ptr삭제 하고 스페셜 이 삭제 될 때 이동 하는 구현을 상상할 수 있습니다 . 구현이 준수하는 것처럼 보이지만 특히 사용 횟수에 제어 블록이 필요할 수 있기 때문에 이상합니다.

내가 찾은 관련 예탁 증서 : 545 , 575 , 2434 , (모든 구현이 제어 블록을 사용하는 것을 인정 다소을 의무화하는 멀티 스레딩 제약을 의미하는 것) 2802 Deleter가 만 작도 이동해야하는 (따라서 구현 어디 방지 삭제는 여러 개의 사이에 복사됩니다 shared_ptr).


답변

에서 표준 : : shared_ptr의 우리가 있습니다 :

제어 블록은 다음을 보유한 동적으로 할당 된 객체입니다.

  • 관리 객체 또는 관리 객체 자체에 대한 포인터;
  • 삭제 기 (유형 소거);
  • 할당 자 (유형 소거);
  • 관리 객체를 소유 한 shared_ptr의 수;
  • 관리 객체를 나타내는 weak_ptr의 수

그리고 std :: allocate_shared에서 다음 을 얻습니다.

template< class T, class Alloc, class... Args >
shared_ptr<T> allocate_shared( const Alloc& alloc, Args&&... args );

공유 포인터 의 제어 블록 과 T 개체 모두에 대해 하나의 할당 을 사용하기 위해 T 형식의 개체를 구성하고 std :: shared_ptr […]에 래핑 합니다.

그래서처럼 보이는 표준 : allocate_shared 를 할당해야 deleter당신과 함께 Alloc.

편집 : 그리고 n4810§20.11.3.6 생성 [util.smartptr.shared.create]

모두에 적용되는 1 개 공통 요구 사항은 make_shared, allocate_shared, make_shared_default_init,와 allocate_shared_default_init달리 명시되지 않는 한 과부하, 아래에 설명되어 있습니다.

[…]

7 비고 : (7.1) — 구현은 하나 이상의 메모리 할당을 수행하지 않아야합니다. [참고 : 이것은 침입 스마트 포인터와 동등한 효율성을 제공합니다. — 끝 참고]

[모든 것의 헛소리]

표준 그래서 말하는 std::allocate_shared 해야 사용 Alloc제어 블록.


답변

나는 이것이 불특정이라고 믿는다.

관련 생성자의 사양은 다음과 같습니다. [util.smartptr.shared.const] / 10

template<class Y, class D> shared_ptr(Y* p, D d);
template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template <class D> shared_ptr(nullptr_t p, D d);
template <class D, class A> shared_ptr(nullptr_t p, D d, A a);

효과 : 구축 shared_­ptr객체 소유 객체 p와 Deleter가를 d. 되면 T배열 유형이 아닌, 제 1 및 제 2 활성화 생성자 shared_­from_­thisp. 두 번째와 네 번째 생성자 a내부 용으로 메모리를 할당 하기 위해 사본을 사용해야 합니다. 예외가 발생하면 d(p)이 호출됩니다.

이제 내 구현에는 내부 사용을 위해 메모리가 필요할 때을 사용하여 수행된다는 해석이 a있습니다. 구현에서이 메모리를 사용하여 모든 것을 배치해야한다는 의미는 아닙니다. 예를 들어, 이상한 구현이 있다고 가정하십시오.

template <typename T>
class shared_ptr : /* ... */ {
    // ...
    std::aligned_storage<16> _Small_deleter;
    // ...
public:
    // ...
    template <class _D, class _A>
    shared_ptr(nullptr_t, _D __d, _A __a) // for example
        : _Allocator_base{__a}
    {
        if constexpr (sizeof(_D) <= 16)
            _Construct_at(&_Small_deleter, std::move(__d));
        else
            // use 'a' to allocate storage for the deleter
    }
// ...
};

이 구현이 “사본을 a위해 메모리를 할당 하기 위해 사본을 사용합니까?” 그렇습니다. 를 사용하지 않고는 메모리를 할당하지 않습니다 a. 이 순진한 구현에는 많은 문제가 있지만 shared_ptr포인터에서 직접 생성되고 결코 복사되거나 이동되거나 참조되지 않으며 다른 합병증이없는 가장 단순한 경우를 제외하고 할당자를 사용하도록 전환한다고 가정 해 봅시다 . 요점은, 우리가 유효한 구현이 그 자체로는 이론적으로 존재할 수 없다는 것을 증명하지 못한다고 상상하지 못하기 때문입니다. 나는 실제로 그러한 구현이 실제 세계에서 발견 될 수 있다고 말하지는 않으며 표준이 적극적으로 그것을 금지하지 않는 것 같습니다.


답변