Aby utworzyć obiekt B
w prawidłowym stanie, nie trzeba nic więcej robić. Nawet nie musisz deklarować i implementować konstruktora i destruktora dla B
. std::vector<std::shared_ptr<A>>
, który jest członkiem B
zostanie domyślnie zainicjowany w konstruktorze B
, co oznacza, że nie ma jeszcze żadnych elementów w kontenerze. Zostanie on również poprawnie usunięty w ~B
dzięki destruktorom std::vector
i.
Z drugiej strony, jeśli chcesz np. Zainicjować go w jakiś sposób (tj.3 wartości) można użyć konstruktora std::vector
's na liście inicjalizującej konstruktora B
. Na przykład:
class B
{
public:
B(): _innerArray{ std::make_shared<A>(),
std::make_shared<A>(),
std::make_shared<A>() } {}
~B() {}
private:
std::vector<std::shared_ptr<A>> _innerArray;
};
Pamiętaj, że std::make_shared
wykorzystuje doskonałe przekazywanie więc zdać A
argumenty „s konstruktora jako argumentów funkcji, a nie sam obiekt klasy.
Odpowiadając na twoje obawy dotyczące projektu, chciałabym Cię zachęcić, aby najpierw pomyślał o wyłącznej własności członków w wektorze, zanim zdecydujesz się je udostępnić.
class B
{
public:
B();
~B();
private:
std::vector<std::unique_ptr<A>> _innerArray;
};
Powyższa implementacja jest bardziej skuteczna na wielu podstawach. Przede wszystkim sprawia, że Twój projekt jest bardziej przejrzysty w kwestii tego, kto jest odpowiedzialny za całe życie A
. Następna std::unique_ptr
jest szybsza, ponieważ nie wymaga liczenia odwołań do wątków. I na koniec, nie kosztuje żadnej dodatkowej pamięci (w porównaniu do zwykłego wskaźnika C), podczas gdy std::shared_ptr
może zająć dziesiątki bajtów (24-48), aby przechowywać dane stanu współdzielonego, co jest wysoce nieskuteczne, gdy operujesz na małych klasach. Dlatego zawsze używam std::unique_ptr
jako mojego pierwszego inteligentnego wskaźnika pointeru, a ja tylko cofam się do std::shared_ptr
, gdy jest to naprawdę potrzebne.
EDIT:
Odpowiadając edycję chciałbym stworzyć 3 pojemniki klas A
, B
, C
. W zależności od tego, czy trzeba im być polimorficzny lub nie będzie przechowywać zarówno wartości tak (typu non-polimorficzne):
std::deque<A> as;
std::deque<B> bs;
std::deque<C> cs;
lub (typy polimorficzne):
std::vector<std::unique_ptr<A>> as;
std::vector<std::unique_ptr<B>> bs;
std::vector<std::unique_ptr<C>> cs;
w tej kolejności (as
musi żyć dłużej niż bs
i bs
musi żyć dłużej niż cs
). Wtedy po prostu miałbym std::vector<A*>
wewnątrz klasy B
i std::vector<B*>
wewnątrz klasy C
bez użycia inteligentnych wskaźników.
Mam nadzieję, że to pomaga.
EDIT:
Zmieniono std::vector
do std::deque
w pierwszym przypadku, który pozwala referencje/wskaźniki do elementów kontenerowych przetrwać kontenery rozszerzeń z push_back()
. Jednak nie przetrwają wymazania elementów, sortowania lub innych rzeczy.
Kontrola poczytalności: czy w ogóle potrzebujesz wskazówki? A jeśli tak, czy powinien to być wspólny wskaźnik? –
Klasa B powinna mieć dostęp do niektórych obiektów przechowywanych gdzie indziej, ale nie do nich należeć. Nie widzę używania unique_ptr zamiast shared_ptr w sensie tutaj, ale jestem noob do inteligentnych wskaźników. –
@Pavel Masz rację: Twój scenariusz wyklucza użycie 'unique_ptr' i nakazuje użycie wskaźników. Jednakże, jeśli 'B' nie ma przejąć własności, rozważałbym użycie surowych wskaźników zamiast wspólnych wskaźników. W końcu te ostatnie oznaczają * własność współdzieloną * (ale być może tego właśnie potrzebujesz). –