6.3 KiB
6.3 KiB
Efficiency
Raw pointer
#include <memory>
#include <vector>
struct Data {
char tab_[42];
};
int main(void) {
constexpr unsigned size = 10u * 1000u * 1000u;
std::vector<Data *> v;
v.reserve(size);
for (unsigned i = 0; i < size; ++i) {
auto p = new Data;
v.push_back(std::move(p));
}
for (auto p: v)
delete p;
}
Unique pointer
#include <memory>
#include <vector>
struct Data {
char tab_[42];
};
int main(void) {
constexpr unsigned size = 10u * 1000u * 1000u;
std::vector<std::unique_ptr<Data>> v;
v.reserve(size);
for (unsigned i = 0; i < size; ++i) {
std::unique_ptr<Data> p{new Data};
v.push_back(std::move(p));
}
}
Shared pointer
#include <memory>
#include <vector>
struct Data {
char tab_[42];
};
int main(void) {
constexpr unsigned size = 10u * 1000u * 1000u;
std::vector<std::shared_ptr<Data>> v;
v.reserve(size);
for (unsigned i = 0; i < size; ++i) {
std::shared_ptr<Data> p{new Data};
v.push_back(std::move(p));
}
}
Shared pointer – make_shared
#include <memory>
#include <vector>
struct Data {
char tab_[42];
};
int main(void) {
constexpr unsigned size = 10u * 1000u * 1000u;
std::vector<std::shared_ptr<Data>> v;
v.reserve(size);
for (unsigned i = 0; i < size; ++i) {
auto p = std::make_shared<Data>();
v.push_back(std::move(p));
}
}
Weak pointer
#include <memory>
#include <vector>
struct Data {
char tab_[42];
};
int main(void) {
constexpr unsigned size = 10u * 1000u * 1000u;
std::vector<std::shared_ptr<Data>> vs;
std::vector<std::weak_ptr<Data>> vw;
vs.reserve(size);
vw.reserve(size);
for (unsigned i = 0; i < size; ++i) {
std::shared_ptr<Data> p{new Data};
std::weak_ptr<Data> w{p};
vs.push_back(std::move(p));
vw.push_back(std::move(w));
}
}
Measurements
- gcc-4.8.2
-
compilation with
–std=c++11 –O3 –DNDEBUG -
measuring with:
- time (real)
- htop (mem)
- valgrind (allocations count)
Results
| test name | time [s] | allocations | memory [MB] |
|---|---|---|---|
| raw pointer | 0.54 | 10 000 001 | 686 |
| unique pointer | 0.56 | 10 000 001 | 686 |
| shared pointer | 1.00 | 20 000 001 | 1072 |
| make shared | 0.76 | 10 000 001 | 914 |
| weak pointer | 1.28 | 20 000 002 | 1222 |
Conclusions
-
RAII
- acquire resource in constructor
- release resource in destructor
- Rule of 5, Rule of 0
-
Smart pointers:
-
std::unique_ptr– primary choice, no overhead, can convert tostd::shared_ptr -
std::shared_ptr– introduces memory and runtime overhead -
std::weak_ptr– breaking cycles, can convert to/fromstd::shared_ptr
-
-
Create smart pointers with
std::make_shared()andstd::make_unique() - Raw pointer should mean „access only” (no ownership)
- Use reference instead of pointers if possible
Post-work
-
Transform the list from
List.cppinto double-linked list. You should implement:- inserting Nodes at the beginning of the list
- searching elements in reverse
- Apply proper smart pointers for the reverse direction.
-
Implement your own
unique_ptr. Requirements:- Templatized (should hold a pointer to a template type)
- RAII (acquire in constructor, release in destructor)
- Copying not allowed
- Moving allowed
-
Member functions:
operator*(),operator->(),get(),release(),reset()
-
Read one of these articles on move semantics:
- Semantyka przenoszenia (in Polish)
- Move semantics and rvalue references in C++11 (in English)