Этот вопрос касается владения указателями, их использования, умных указателей, векторов и распределителей.
Я немного заблудился в своих мыслях об архитектуре кода. Кроме того, если на этот вопрос уже есть где-то ответ, 1. извините, но я до сих пор не нашел удовлетворительного ответа и 2. пожалуйста, укажите мне на него.
Моя проблема заключается в следующем:
У меня есть несколько "вещей", хранящихся в векторе, и несколько "потребителей" этих "вещей". Итак, моя первая попытка была такой:
std::vector<thing> i_am_the_owner_of_things;
thing* get_thing_for_consumer() {
// some thing-selection logic
return &i_am_the_owner_of_things[5]; // 5 is just an example
}
...
// somewhere else in the code:
class consumer {
consumer() {
m_thing = get_thing_for_consumer();
}
thing* m_thing;
};
В моем приложении это было бы безопасно, потому что "вещи" переживают "потребителей" в любом случае. Однако во время выполнения можно добавить больше "вещей", и это может стать проблемой, потому что если std::vector<thing> i_am_the_owner_of_things;
перераспределяется, все указатели thing* m_thing
становятся недействительными.
Исправление в этом сценарии состояло бы в том, чтобы хранить уникальные указатели на "вещи" вместо "вещей" напрямую, то есть следующим образом:
std::vector<std::unique_ptr<thing>> i_am_the_owner_of_things;
thing* get_thing_for_consumer() {
// some thing-selection logic
return i_am_the_owner_of_things[5].get(); // 5 is just an example
}
...
// somewhere else in the code:
class consumer {
consumer() {
m_thing = get_thing_for_consumer();
}
thing* m_thing;
};
Недостатком здесь является то, что когерентность памяти между "вещами" теряется. Может ли эта когерентность памяти быть восстановлена с помощью пользовательских распределителей как-то? Я имею в виду нечто вроде распределителя, который всегда выделял бы память, например, для 10 элементов за раз, и всякий раз, когда требовалось, добавлял больше кусков памяти размером 10 элементов.
Пример:
первоначально:
v = ☐☐☐☐☐☐☐☐☐☐
больше элементов:
v = ☐☐☐☐☐☐☐☐☐☐ 🡒 ☐☐☐☐☐☐☐☐☐☐
и опять:
v = ☐☐☐☐☐☐☐☐☐☐ 🡒 ☐☐☐☐☐☐☐☐☐☐ 🡒 ☐☐☐☐☐☐☐☐☐☐
Используя такой распределитель, мне даже не пришлось бы использовать std::unique_ptr
для "вещей", потому что во время перераспределения std::vector
адреса памяти уже существующих элементов не изменились бы.
В качестве альтернативы я могу думать только о том, чтобы ссылаться на "вещь" в "потребителе" через std::shared_ptr<thing> m_thing
, в отличие от текущей thing* m_thing
но это кажется мне худшим подходом, потому что "вещь "не должен владеть" потребителем ", и с помощью общих указателей я бы создал совместное владение.
Итак, подход распределителя хорош? И если так, как это можно сделать? Должен ли я сам применять распределитель или он существует?