Этот вопрос касается владения указателями, их использования, умных указателей, векторов и распределителей.
Я немного растерялся, думая об архитектуре кода. Кроме того, если на этот вопрос уже есть где-то ответ, 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
, но это кажется мне наихудшим подходом, потому что «вещь» должна Я не являюсь владельцем "потребителя", и с помощью общих указателей я бы создал общее владение.
Итак, подход распределителя хорош? И если так, как это можно сделать? Должен ли я сам применять распределитель или он существует?