Program Club

C ++ 14에서 new 및 delete가 여전히 유용합니까?

proclub 2020. 12. 9. 20:53
반응형

C ++ 14에서 new 및 delete가 여전히 유용합니까?


의 가용성을 감안할 make_uniquemake_shared에 의해뿐만 아니라 자동으로 삭제 unique_ptrshared_ptr소멸자 사용을 위해 (떨어져 레거시 코드를 지원에서) 상황 무엇 newdelete++ (14) C에가?


스마트 포인터가 많은 경우 원시 포인터에 바람직하지만,에 대한 사용 사례가 많이 아직 없습니다 new/ delete14 C ++에서이.

내부 구성이 필요한 내용을 작성해야하는 경우 예를 들면 다음과 같습니다.

  • 메모리 풀
  • 할당 자
  • 태그가 지정된 변형
  • 이진 메시지를 버퍼로

배치 new및 가능하면 delete. 그럴 방법이 없습니다.

작성하려는 일부 컨테이너의 경우 저장을 위해 원시 포인터를 사용할 수 있습니다.

심지어 표준 스마트 포인터를 들어, 당신은 여전히 필요합니다 new당신이 있기 때문에 사용자 정의 deleters을 사용하려는 경우 make_uniquemake_shared그 허용하지 않습니다.


그것은 사용하는 비교적 흔한 선택 make_unique하고 make_shared오히려 원시 호출보다 new. 그러나 필수는 아닙니다. 이 규칙을 따르기로 선택했다고 가정하면 몇 군데를 사용할 수 있습니다 new.

첫째, 비 커스텀 배치 new( "비 커스텀"부분은 무시하고 배치라고 부릅니다 new)는 표준 (비 배치)와는 완전히 다른 카드 게임 new입니다. 소멸자를 수동으로 호출하는 것과 논리적으로 쌍을 이룹니다. Standard new는 무료 상점에서 리소스를 획득하고 그 안에 객체를 생성합니다. 와 쌍을 delete이루며 객체를 파괴하고 저장소를 무료 저장소로 재활용합니다. 어떤 의미에서 표준 newnew내부적으로 배치를 delete호출 하고 표준 은 내부적으로 소멸자를 호출합니다.

배치 new는 일부 저장소에서 생성자를 직접 호출하는 방법이며 고급 수명 관리 코드에 필요합니다. 당신이 구현하는 경우 optional, 유형 안전 union정렬 스토리지에, 또는 (같은 통합 스토리지 및 비 통합 수명과 스마트 포인터를 make_shared), 당신은 위치를 사용하는 것입니다 new. 그런 다음 특정 개체의 수명이 끝나면 직접 소멸자를 호출합니다. 비 배치 같이 new하고 delete, 배치 new및 수동 소멸자 통화 쌍으로.

사용자 지정 배치는를 new사용하는 또 다른 이유 new입니다. 사용자 지정 배치 new를 사용하여 비 글로벌 풀에서 리소스를 할당 할 수 있습니다 (범위 할당 또는 교차 프로세스 공유 메모리 페이지로의 할당, 비디오 카드 공유 메모리로의 할당 등) 및 기타 목적. make_unique_from_custom커스텀 배치를 사용하여 메모리를 할당하는 것을 작성 하려면 new new키워드 를 사용해야합니다 . 사용자 지정 배치 new는 새로운 배치처럼 작동하거나 (실제로 리소스를 획득하는 것이 아니라 리소스가 어떻게 든 전달 new된다는 점에서) 표준처럼 작동 할 수 있습니다 (전달 된 인수를 사용하여 자원을 획득한다는 점에서).

커스텀 배치 delete가 발생하면 커스텀 배치 가 호출 new되므로 작성해야 할 수도 있습니다. C ++에서 사용자 지정 배치를 호출하지 않는 delete것이, (C는 ++) 을 호출 (R 과부하) .

마지막으로, make_shared그리고 make_unique그들이 정의 deleters을 지원하지 않는 점에서 불완전한 기능은 다음과 같습니다.

를 작성하는 경우 make_unique_with_deleter에도 make_unique데이터를 할당하는 데 사용할 수 있으며 삭제 자 .release()에게 고유 한 관리를 제공합니다. 삭제자가 자신의 상태를 unique_ptr별도의 할당 또는 별도의 할당 대신 지적 된 버퍼에 채우려는 경우 new여기에 배치를 사용해야 합니다.

의 경우 make_shared클라이언트 코드는 "참조 계산 스텁"생성 코드에 액세스 할 수 없습니다. 내가 말할 수있는 한 "객체 및 참조 계수 블록의 결합 된 할당"과 사용자 지정 삭제자를 모두 쉽게 가질 수는 없습니다.

또한 make_shared객체 자체에 대한 리소스 할당 (스토리지)이 지속되는 한 지속 weak_ptr되도록합니다. 어떤 경우에는 이것이 바람직하지 않을 수 있으므로 shared_ptr<T>(new T(...))이를 방지하기 위해 a 수행하는 것이 좋습니다.

non-placement를 호출하려는 몇 가지 경우에는을 호출 한 다음 그 와 별도로 관리하려는 경우 포인터를 new호출 할 수 있습니다 . 이렇게하면 리소스에 대한 RAII 범위가 증가하고 예외 또는 기타 논리 오류가있는 경우 유출 가능성이 줄어 듭니다.make_unique.release()unique_ptr


위에서 언급했듯이 단일 할당 블록을 쉽게 사용하는 공유 포인터가있는 사용자 지정 삭제자를 사용하는 방법을 몰랐습니다. 다음은이를 교묘하게 수행하는 방법에 대한 스케치입니다.

template<class T, class D>
struct custom_delete {
  std::tuple<
    std::aligned_storage< sizeof(T), alignof(T) >,
    D,
    bool
  > data;
  bool bCreated() const { return std::get<2>(data); }
  void markAsCreated() { std::get<2>()=true; }
  D&& d()&& { return std::get<1>(std::move(data)); }
  void* buff() { return &std::get<0>(data); }
  T* t() { return static_cast<T*>(static_cast<void*>(buff())); }
  template<class...Ts>
  explicit custom_delete(Ts...&&ts):data(
    {},D(std::forward<Ts>(ts)...),false
  ){}
  custom_delete(custom_delete&&)=default;
  ~custom_delete() {
    if (bCreated())
      std::move(*this).d()(t());
  }
};

template<class T, class D, class...Ts, class dD=std::decay_t<D>>
std::shared_ptr<T> make_shared_with_deleter(
  D&& d,
  Ts&&... ts
) {
  auto internal = std::make_shared<custom_delete<T, dD>>(std::forward<D>(d));
  if (!internal) return {};
  T* r = new(internal->data.buff()) T(std::forward<Ts>(ts...));
  internal->markAsCreated();
  return { internal, r };
}

그렇게해야한다고 생각합니다. 나는 상태 비 저장 삭제자가를 사용하여 공간을 사용하지 못하도록 허용하려고 시도 tuple했지만 실수했을 수 있습니다.

경우 라이브러리 품질의 솔루션에서 T::T(Ts...)이다 noexcept, 나는 제거 할 수 bCreatedA를 위해 더 기회가 없을 것 같은 오버 헤드를 custom_delete가 전에 파괴해야 할 T구성된다.


내가 생각할 수있는 유일한 이유는 때때로 사용자 지정 삭제자를 unique_ptr또는 shared_ptr. 사용자 지정 삭제자를 사용하려면 스마트 포인터를 직접 만들어 new. 이것은 빈번하지 않지만 실제로 발생합니다.

Other than that it seems that make_shared/make_unique should cover pretty much all uses.


I would say the only reason for new and delete is to implement other kinds of smart pointers.

For example, the library still does not have intrusive pointers as boost::intrusive_ptr, which is a pity since they are superior for performance reasons to shared pointers, as Andrei Alexandrescu points out.

참고URL : https://stackoverflow.com/questions/30762994/are-new-and-delete-still-useful-in-c14

반응형