Я разрабатываю относительно большую библиотеку (~ 13000 строк) в качестве библиотеки личных утилит.Он использует исключительно контейнеры STL и интеллектуальные указатели для управления памятью - но теперь я нахожусь в ситуации, когда я вижу движение к обычным указателям из-за очевидного отсутствия очевидного решения в STL.Я бы хотел сохранить современный стиль C ++.
Вот мой mcve :
Struct Foo
- структура int
-оболочки, отображающая, какие функции-членыбыли вызваны.
struct Foo {
Foo(int x) {
this->x = x;
std::cout << "constructor\n";
}
Foo(const Foo& other) {
this->x = other.x;
std::cout << "copy constructor\n";
}
~Foo() {
std::cout << "destructor\n";
}
int x;
};
Глядя на main
Я создаю автоматический экземпляр struct Foo
:
int main() {
Foo foo{ 0 };
std::cout << "\nfoo.x : " << foo.x << "\n\n";
}
output>
constructor
foo.x : 0
destructor
Просто так,- теперь, если я хочу указать на foo
и манипулировать его содержимым.
Умные указатели, такие как std::unique_ptr
или std::shared_ptr
, не достигнут этого эффекта (очевидно!).Использование std::make_unique<T>()
(/ std::make_shared<T>()
) будет динамически выделять память и копировать только значение:
Foo foo{ 0 };
std::unique_ptr<Foo> ptr = std::make_unique<Foo>(foo);
ptr->x = 2;
std::cout << "\nptr->x : " << ptr->x << '\n';
std::cout << "foo.x : " << foo.x << "\n\n";
output>
constructor
copy constructor
ptr->x : 2
foo.x : 0 // didn't change
destructor
destructor
Так что это не работает.Однако их функция-член void reset(pointer _Ptr = pointer()) noexcept
позволяет напрямую назначать указатель:
std::unique_ptr<Foo> ptr;
Foo foo{ 0 };
ptr.reset(&foo);
ptr->x = 2;
std::cout << "\nptr->x : " << ptr->x << '\n';
std::cout << "foo.x : " << foo.x << "\n\n";
output>
constructor
ptr->x : 2
foo.x : 2
destructor
destructor //crash
Но сбой!foo
get деконструируется нормально, а затем std::shared_ptr
также хочет деконструировать свою уже деконструированную разыменованную стоимость.
HEAP [main.exe]: для RtlValidateHeap указан неправильный адрес (...)
Использование указателя const:
Foo foo{ 0 };
Foo* const ptr = &foo;
ptr->x = 2;
std::cout << "\nptr->x : " << ptr->x << '\n';
std::cout << "foo.x : " << foo.x << "\n\n";
output>
constructor
ptr->x : 2
foo.x : 2
deconstructor
- 1 выделение, 1 освобождение.
- без копирования.
- фактически манипулирует значением.
Пока указатель кажется лучшим вариантом.
Я просто ищу способ указать на автоматически распределенные объекты.Пока что это кажется удивительно трудным, не возвращаясь к простым указателям.
Я сам предоставил одно решение - использование /*const*/ std::reference_wrapper<T>
.(не стесняйтесь поправлять меня по поводу этого решения)
Но я не уверен, какая стратегия лучше.Указатель?std::reference_wrapper
может быть?Я сделал ошибку с использованием std::shared_ptr
/ std::unique_ptr
?
Есть ли лучший, более простой класс STL?