I am developing a relatively large library (~13000 lines) as a personal utility library. It uses exclusively STL containers and smart pointers for memory management - but now I find myself in a situation where I could see going for normal pointers due to an apparent lack of an obvious solution in STL. I would like to maintain a modern C++ style, though.
Here's my mcve:
Struct Foo
- a int
-wrapper struct displaying which member functions were called.
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;
};
Looking at main
I create an automatic instance of struct Foo
:
int main() {
Foo foo{ 0 };
std::cout << "\nfoo.x : " << foo.x << "\n\n";
}
output >
constructor
foo.x : 0
destructor
Easy as that. - now if I want to point to foo
and manipulate its content.
Smart pointers like std::unique_ptr
or std::shared_ptr
won't achieve this effect (apparently!). Using std::make_unique<T>()
(/ std::make_shared<T>()
) will dynamically allocate memory and only copy the value:
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
So that's not working. However, their void reset(pointer _Ptr = pointer()) noexcept
member function allows to directly assign a pointer:
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
But crash! foo
get's deconstructed normally and than std::shared_ptr
also wants to deconstruct its already deconstructed dereferenced value.
HEAP[main.exe]: Invalid address specified to RtlValidateHeap(...)
Using a const pointer:
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 allocation, 1 deallocation.
- no copying.
- actually manipulating the value.
So far the pointer feels like the best option.
I am just looking for a way to point to automatically allocated objects. So far it seems surprisingly difficult without going back to plain pointers.
I provided one solution by myself - which is using /*const*/ std::reference_wrapper<T>
. (feel free to correct me about this solution)
But I am not sure what's the best strategy. The pointer? the std::reference_wrapper
maybe? Did I made a mistake with using std::shared_ptr
/ std::unique_ptr
?
Is there a better, more straightforward STL class?