4.7 KiB
4.7 KiB
std::shared_ptr<>
std::shared_ptr<>
- one object == multiple owners
- last referrer destroys the object
- copying allowed
- moving allowed
- can use custom deleter
- can use custom allocator
- has a control block == impact on size of pointer end efficiency
std::shared_ptr<> usage (1)
- Copying and moving is allowed
std::shared_ptr<MyData> source();
void sink(std::shared_ptr<MyData> ptr);
void simpleUsage() {
source();
sink(source());
auto ptr = source();
sink(ptr);
sink(std::move(ptr));
auto p1 = source();
auto p2 = p1;
p2 = std::move(p1);
p1 = p2;
p1 = std::move(p2);
}
std::shared_ptr<MyData> source();
void sink(std::shared_ptr<MyData> ptr);
void collections() {
std::vector<std::shared_ptr<MyData>> v;
v.push_back(source());
auto tmp = source();
v.push_back(tmp);
v.push_back(std::move(tmp));
sink(v[0]);
sink(std::move(v[0]));
}
std::shared_ptr<> usage (2)
#include <memory>
#include <map>
#include <string>
class Gadget {};
std::map<std::string, std::shared_ptr<Gadget>> gadgets;
void foo() {
std::shared_ptr<Gadget> p1{new Gadget()}; // reference counter = 1
{
auto p2 = p1; // copy (reference counter == 2)
gadgets.insert(make_pair("mp3", p2)); // copy (reference counter == 3)
p2->use();
} // destruction of p2, reference counter = 2
} // destruction of p1, reference counter = 1
int main() {
foo();
gadgets.clear(); // reference counter = 0 - gadget is removed
}
Custom deleter
-
Don't change a type of
shared_ptrbecause data is stored in control block -
Don't change a size of
shared_ptrbecause data is stored in control block -
You can have a collection of
shared_ptrwhich has different deleter
class Foo {};
void deleter1(Foo* const foo) {
std::cout << "Deleter1\n";
delete foo;
}
int main() {
std::vector<std::shared_ptr<Foo>> vec;
std::shared_ptr<Foo> ptr1(new Foo(), deleter1);
vec.push_back(std::move(ptr1));
auto deleter2 = [](Foo* const foo) {
std::cout << "Deleter2\n";
delete foo;
};
vec.emplace_back(new Foo(), deleter2);
}
Deleter1
Deleter2
Problem with shared_ptr
Let's look at a short story:
- Programmer1 : Why do you pass shared_ptr by copy? Passing by copy increment counter (slower then unique or raw ptr)
- Programmer2: Ok, so I will pass it by const reference instead! And avoid unnecessary incrementation of the control block.
- Programmer1: So if you don't need to copy it (don't need to have 2 owners) why don't use unique_ptr?
- Reassume: shared_ptr should be use only when given resource need to have few owners (very rare situation). In other case use always unique_ptr!
std::shared_ptr<> cyclic dependencies
- What happens here?
#include <memory>
struct Node {
std::shared_ptr<Node> child;
std::shared_ptr<Node> parent;
};
int main () {
auto root = std::shared_ptr<Node>(new Node);
auto child = std::shared_ptr<Node>(new Node);
root->child = child;
child->parent = root;
}
Memory leak!