簡體   English   中英

為什么std :: unique_ptr沒有像std :: shared_ptr這樣的別名構造函數?

[英]Why doesn't std::unique_ptr have an aliasing constructor like std::shared_ptr has?

我剛剛發現了std::shared_ptr的“別名構造函數”並發現自己在問“為什么std :: unique_ptr沒有相應的一個?

也就是說,如果你想分配一個Foo以便你可以將它的Bar成員傳遞給一個完全可以管理Foo生命周期的函數,那么這樣做是不是很好?

#include <memory>

struct B {}
struct A {
  B b;
}

void f(std::unique_ptr<B> b);

std::unique_ptr<A> a = std::make_unique<A>();
std::unique_ptr<B> b { std::move(a), &(a->b) };  // a now invalid.
f(std::move(b));  // f now responsible for deleting the A.

這適用於std :: shared_ptr( http://ideone.com/pDK1bc

#include <iostream>
#include <memory>
#include <string>

struct B {
  std::string s;
};
struct A {
  B b;
  A(std::string s) : b{s} {};
  ~A() { std::cout << "A deleted." << std::endl; }
};

void f(std::shared_ptr<B> b) {
  std::cout << "in f, b->s = " << b->s << " (use_count=" << b.use_count() << ")" << std::endl;
}

int main() {
  std::shared_ptr<A> a = std::make_shared<A>("hello");
  std::shared_ptr<B> b { a, &(a->b) };
  a.reset();  // a now invalid.
  std::cout << "before f, b->s = " << b->s << " (use_count=" << b.use_count() << ")" << std::endl;
  f(std::move(b));  // f now responsible for deleting the A.
  std::cout << "after f" << std::endl;
  return 0;
}

輸出預期的

before f, b->s = hello (use_count=1)
in f, b->s = hello (use_count=1)
A deleted.
after f

有沒有合理的理由說明為什么不包含這樣的東西? 和/或,使用帶有刪除A的自定義刪除器的unique_ptr<B>來模擬它是不是一個壞主意?

我相信“問題”是,與std::shared_ptr不同, std::unique_ptr的刪除器不是類型擦除的。 std::unique_ptr<T>的默認刪除器(其大小為零,編碼為類型本身作為幾乎不可見的默認類型參數)只是[](T * p){ delete p; } [](T * p){ delete p; } 但很明顯,通過std::make_unique<B>創建的std::make_unique<B>和通過指向A對象的B成員創建的std::unique_ptr<B>不能具有相同的刪除器。 后一種情況的刪除器必須做一些指針運算才能獲得原始的A *指針。 如果兩個刪除器都存儲偏移量或內部指針指向原始對象,那么這兩個刪除器只能具有相同的類型。 那將不再是零大小。 new手動delete和手動delete相比, std::unique_ptr開銷設計為零,這是一件好事。 我沒有看到使用你自己的刪除器存儲額外的指針的任何直接的缺點,雖然我仍然需要遇到一個用例,我發現這有用。

shared_ptr具有引用計數開銷。 在它的引用計數塊中,它還存儲一個顯式的刪除器(因為如果你在堆上存儲,還有幾個字節?)

這也是為什么基類型的shared_ptr可以記住在沒有虛擬dtor的情況下刪除派生類型的原因。

另一方面, unique_ptr將其刪除器存儲在實例中,默認刪除器是無狀態的 - 使用0個字節。 這使得unique_ptr在內存使用方面比原始指針零開銷。

無狀態刪除者不記得刪除別的東西。

您可以向unique_ptr添加一個支持別名的有狀態刪除器,但是您必須手動設置別名。 其中一個構造函數同時使用指針和刪除器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM