簡介
將一個 shared_ptr 賦值給一個 weak_ptr 類型的變量時,該 weak_ptr 便屬於 該 shared_ptr 所屬的 owing group 。但與 shared_ptr不同的是,weak_ptr 不會獲取指針的所有權,亦即該指針的屬主數並不會加一。
其存在的目的是爲了打破 shared_ptr 造成的循環引用。如:
#include <iostream>
#include <memory>
using namespace std;
struct Node {
int value;
shared_ptr<Node> parent, left, right;
Node(int value, shared_ptr<Node> parent, shared_ptr<Node> left, shared_ptr<Node> right) {
this->value = value;
this->parent = parent;
this->left = left;
this->right = right;
}
~Node() {
cout << "delete " << value << endl;
}
};
int main() {
shared_ptr<Node> root = make_shared<Node>(1, nullptr, nullptr, nullptr);
// 孩子節點引用父節點
shared_ptr<Node> left = make_shared<Node>(2, root, nullptr, nullptr);
shared_ptr<Node> right = make_shared<Node>(3, root, nullptr, nullptr);
// 父節點引用子節點 -> 循環引用,誰都死不了,內存無法釋放!
root->left = left;
root->right = right;
return 0;
}
什麼都不輸出。當 left/right 離開作用域時,其 stored pointer 的屬主數減一,變爲了1(不爲 0),所以它指向的 Node 對象無法被銷燬。當 root 離開作用域時,其 stored pointer 的屬主數減一,變爲了 2 ,所以它指向的 Node 對象也無法被銷燬。
改用 weak_ptr:
#include <iostream>
#include <memory>
using namespace std;
struct Node {
int value;
weak_ptr<Node> parent;
shared_ptr<Node> left, right;
Node(int value, weak_ptr<Node> parent, shared_ptr<Node> left, shared_ptr<Node> right) {
this->value = value;
this->parent = parent;
this->left = left;
this->right = right;
}
~Node() {
cout << "delete " << value << endl;
}
};
int main() {
shared_ptr<Node> root = make_shared<Node>(1, weak_ptr<Node>(), nullptr, nullptr);
shared_ptr<Node> left = make_shared<Node>(2, root, nullptr, nullptr);
shared_ptr<Node> right = make_shared<Node>(3, root, nullptr, nullptr);
root->left = left;
root->right = right;
return 0;
}
delete 1
delete 3
delete 2
構造
default (1) | constexpr weak_ptr() noexcept; |
---|---|
copy (2) | weak_ptr (const weak_ptr& x) noexcept; template <class U> weak_ptr (const weak_ptr<U>& x) noexcept; |
from shared_ptr (3) | template <class U> weak_ptr (const shared_ptr<U>& x) noexcept; |
move (4) | weak_ptr (weak_ptr&& x) noexcept; template <class U> weak_ptr (weak_ptr<U>&& x) noexcept; |
注意:無法使用 nullptr
構造 weak_ptr !
// weak_ptr constructor example
#include <iostream>
#include <memory>
struct C {int* data;};
int main () {
std::shared_ptr<int> sp (new int);
std::weak_ptr<int> wp1;
std::weak_ptr<int> wp2 (wp1);
std::weak_ptr<int> wp3 (sp);
std::cout << "use_count:\n";
std::cout << "wp1: " << wp1.use_count() << '\n';
std::cout << "wp2: " << wp2.use_count() << '\n';
std::cout << "wp3: " << wp3.use_count() << '\n';
return 0;
}
use_count:
wp1: 0
wp2: 0
wp3: 1
賦值
copy (1) | weak_ptr& operator= (const weak_ptr& x) noexcept; template <class U> weak_ptr& operator= (const weak_ptr<U>& x) noexcept; |
---|---|
from shared_ptr (2) | template <class U> weak_ptr& operator= (const shared_ptr<U>& x) noexcept; |
move (3) | weak_ptr& operator= (weak_ptr&& x) noexcept; template <class U> weak_ptr& operator= (weak_ptr<U>&& x) noexcept; |
注意:無法將 nullptr
賦值給 weak_ptr !
// weak_ptr::operator= example
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> sp1,sp2;
std::weak_ptr<int> wp;
// sharing group:
// --------------
sp1 = std::make_shared<int> (10); // sp1
wp = sp1; // sp1, wp
sp2 = wp.lock(); // sp1, wp, sp2
sp1.reset(); // wp, sp2
sp1 = wp.lock(); // sp1, wp, sp2
std::cout << "*sp1: " << *sp1 << '\n';
std::cout << "*sp2: " << *sp2 << '\n';
return 0;
}
*sp1: 10
*sp2: 10
重置
void reset() noexcept;
置爲 empty 。
// weak_ptr::reset example
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> sp (new int(10));
std::weak_ptr<int> wp(sp);
std::cout << "1. wp " << (wp.expired()?"is":"is not") << " expired\n";
wp.reset();
std::cout << "2. wp " << (wp.expired()?"is":"is not") << " expired\n";
return 0;
}
1. wp is not expired
2. wp is expired
升級爲 shared_ptr
bool expired() const noexcept;
如果該 weak_ptr 爲 empty 、或 owner group 中已經沒有 shared_ptr ,則返回 true 。
// weak_ptr::expired example
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> sp (new int(10));
std::weak_ptr<int> wp(sp);
std::cout << "1. wp " << (wp.expired()?"is":"is not") << " expired\n";
wp.reset();
std::cout << "2. wp " << (wp.expired()?"is":"is not") << " expired\n";
return 0;
}
1. wp is not expired
2. wp is expired
shared_ptr<element_type> lock() const noexcept;
如果還未過期,則返回關聯的 shared_ptr ;如果已經過期,則返回一個 empty 的 shared_ptr 。(原子操作)
// weak_ptr::lock example
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> sp1,sp2;
std::weak_ptr<int> wp;
// sharing group:
// --------------
sp1 = std::make_shared<int> (20); // sp1
wp = sp1; // sp1, wp
sp2 = wp.lock(); // sp1, wp, sp2
sp1.reset(); // wp, sp2
sp1 = wp.lock(); // sp1, wp, sp2
std::cout << "*sp1: " << *sp1 << '\n';
std::cout << "*sp2: " << *sp2 << '\n';
return 0;
}
*sp1: 20
*sp2: 20
交換
成員函數 | void swap (weak_ptr& x) noexcept; |
---|---|
非成員函數 | template <class T> void swap (weak_ptr<T>& x, weak_ptr<T>& y) noexcept; |
交換所屬的組。
// weak_ptr::swap example
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> sp1 (new int(10));
std::shared_ptr<int> sp2 (new int(20));
std::weak_ptr<int> wp1(sp1);
std::weak_ptr<int> wp2(sp2);
wp1.swap(wp2);
std::cout << "sp1 -> " << *sp1 << '\n';
std::cout << "sp2 -> " << *sp2 << '\n';
std::cout << "wp1 -> " << *wp1.lock() << '\n';
std::cout << "wp2 -> " << *wp2.lock() << '\n';
return 0;
}
sp1 -> 10
sp2 -> 20
wp1 -> 20
wp2 -> 10
// weak_ptr swap specialization
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> sp1 (new int(10));
std::shared_ptr<int> sp2 (new int(20));
std::weak_ptr<int> wp1(sp1);
std::weak_ptr<int> wp2(sp2);
swap(wp1,wp2);
std::cout << "sp1 -> " << *sp1 << '\n';
std::cout << "sp2 -> " << *sp2 << '\n';
std::cout << "wp1 -> " << *wp1.lock() << '\n';
std::cout << "wp2 -> " << *wp2.lock() << '\n';
return 0;
}
foo: 20
bar: 10
其他操作
long int use_count() const noexcept;
獲取所在的 owing group 中 shared_ptr 的數目。
不支持比較!