https://en.cppreference.com/w/cpp/memory/shared_ptr/use_count状态:
在多线程环境中,use_count 返回的值是近似值(典型实现使用 memory_order_relaxed 加载)
但这是否意味着use_count()在多线程环境中完全没有用呢?
考虑以下示例,其中该类Circular实现了一个循环缓冲区std::shared_ptr<int>。
向用户提供了一种方法 - ,它检查中元素get()的引用计数是否大于 1(我们不希望这样做,因为这意味着它由先前调用 的用户持有)。nextstd::array<std::shared_ptr<int>>get()
如果是<= 1,则将 的副本std::shared_ptr<int>返回给用户。
在这种情况下,用户是两个线程,除了喜欢调用get()循环缓冲区之外什么都不做——这就是他们的人生目的。
在实践中,当我执行该程序时,它会运行几个周期(通过将 a 添加counter到循环缓冲区类进行测试),然后抛出异常,抱怨下一个元素的引用计数器为> 1。
use_count()这是多线程环境下返回的值是近似值这一说法的结果吗?
是否有可能调整底层机制,使其具有确定性并按照我希望的方式运行?
如果我的想法是正确的 -在 的函数内部,元素use_count()的(或者更确切地说,用户的实际数量)next永远不应该增加到 1 以上,因为只有两个消费者,并且每次线程调用 时,它已经释放了旧的(已复制)(这又意味着剩余的驻留应该只有 1 的引用计数)。get()Circularget()std::shared_ptr<int>std::shared_ptr<int>Circular::ints_
#include <mutex>
#include <array>
#include <memory>
#include <exception>
#include <thread>
class Circular {
public:
Circular() {
for …Run Code Online (Sandbox Code Playgroud) 考虑以下示例类:
class Foo {
public:
void* const arr_;
Foo() = delete;
Foo(const size_t size, bool high_precision) :
arr_(Initialize(size, high_precision)) {};
template <typename T>
T* GetDataPointer() {
return (T* const)arr_;
}
private:
static void* Initialize(const size_t size, bool high_prec) {
if (high_prec) {
return new double[size];
}
else {
return new float[size];
}
}
};
Run Code Online (Sandbox Code Playgroud)
当我使用 创建指向 Foo 对象的共享指针时std::make_shared,我经常发现我初始化的数组数据显示未定义的行为/变得损坏。例如:
std::shared_ptr<Foo> sp_foo = std::make_shared<Foo>(Foo(3,false));
auto foo_data = sp_foo->GetDataPointer<float>();
foo_data[0] = 1.1;
foo_data[1] = 2.2;
foo_data[2] = 3.3;
std::cout << "First …Run Code Online (Sandbox Code Playgroud) 我想在 lambda 表达式中捕获共享指针。尝试了两种方法:
\n捕获共享指针
\n错误:非静态数据成员 A::ptr 的使用无效
\n创建一个弱指针并捕获它(通过网上的一些结果找到这个)。我不确定我的做法是否正确
\n错误: \xe2\x80\x98const 类 std::weak_ptr\xe2\x80\x99 没有名为 \xe2\x80\x98someFunction\xe2\x80\x99 的成员
\n在有人将其标记为重复之前,我知道它可能与其他一些问题类似,但他们的解决方案似乎都不适合我。想知道我做错了什么以及如何解决它,这就是我来这里的原因。
\n文件.h
\n#include "file2.h"\n\nclass A{\n private:\n uint doSomething();\n std::shared_ptr<file2> ptr;\n}\nRun Code Online (Sandbox Code Playgroud)\n文件.cpp
\n#include "file.h"\n\nuint A::doSomething(){\n ...\n\n // Tried using weak pointer\n //std::weak_ptr<Z> Ptr = std::make_shared<Z>();\n \n auto t1 = [ptr](){\n auto value = ptr->someFunction;}\n \n // auto t1 = [Ptr](){\n // auto value = Ptr.someFunction;}\n \n ...\n }\nRun Code Online (Sandbox Code Playgroud)\n _Sp_counted_base使用原子计数器的实现:
_Atomic_word _M_use_count; // #shared
_Atomic_word _M_weak_count; // #weak + (#shared != 0)
Run Code Online (Sandbox Code Playgroud)
为什么计数器是原子的而指针不是?原子计数有必要吗?有没有例子说明其必要性?
(因为std::shared_ptr不是线程安全的,所以我认为原子计数是没有必要的。)
C++ 标准提供了一个别名构造函数shared_ptr:
template <typename T>\nclass shared_ptr\n{\n template <typename U>\n shared_ptr(const shared_ptr<U>& r, element_type* ptr);\n};\nRun Code Online (Sandbox Code Playgroud)\n这样的构造函数意味着一个shared_ptr对象可以以一种方式创建,它拥有一个对象,与 所拥有的相同r,同时存储指向另一个对象的指针 - ptr。
此外,标准明确允许使用此构造函数创建一个shared_ptr不拥有任何东西的对象(从而满足“空”的定义),但仍然指向某个对象(因此被限定为“非空”) :
\n\n[util.smartptr.shared.const]:
\n
\n17。[注2:此构造函数允许使用非空存储指针创建空的shared_\xc2\xadptr 实例。\xe2\x80\x94 尾注]
构造一个空但非空的shared_ptr实例很容易被禁止,例如要求尝试构造shared_ptr具有非空存储指针的空实例应该抛出异常。
但标准选择允许它。我想知道为什么以及为什么。
\n空但非 null 的预期和规范使用场景是什么shared_ptr?
我有一个在线程之间传递的数据类。我希望这个类成为std::shared_ptr唯一一个不能通过从外部调用其析构函数来销毁的类,因此我也希望析构函数是私有的。我目前的解决方案是
template<typename T>
struct DestructorHelper
{
static void Destroy(void* v) { delete static_cast<T*>(v); }
};
class SharedOnly
{
public:
SharedOnly(const SharedOnly& other) = delete; // deleted copy constructor
SharedOnly& operator=(const SharedOnly& other) = delete; // deleted copy assignment operator
SharedOnly(SharedOnly&& other) = delete; // deleted move constructor
SharedOnly& operator=(SharedOnly&& other) = delete; // deleted move assignment operator
static std::shared_ptr<SharedOnly> create()
{
auto objPtr = new SharedOnly;
auto desPtr = &DestructorHelper<SharedOnly>::Destroy;
std::shared_ptr<SharedOnly> shared(objPtr, desPtr);
return shared;
}
private:
SharedOnly() …Run Code Online (Sandbox Code Playgroud) #include <iostream>
#include <memory>
using namespace std;
class Init {
private:
int x;
public:
Init(int y) {
x = y;
cout << "default constructor called" << endl;
}
Init(std::shared_ptr<Init> z) {
this->x = z->x;
cout << "copy constructor called" << endl;
}
};
int main()
{
int k = 5;
std::shared_ptr<Init> a = std::make_shared<Init>(k);
std::shared_ptr<Init> b(a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我的期望是同时调用默认构造函数和复制构造函数,但只调用默认构造函数。可能是什么问题?
输出是: 默认构造函数称为
c++ smart-pointers copy-constructor shared-ptr default-constructor
这是一个关于理解设计决策的问题,而不是对错误或缺陷的抱怨。
在C++标准库中,创建共享指针及其对象的函数是直函数,
template< class T, class... Args> std::shared_ptr<T> make_shared( Args&&... args );
Run Code Online (Sandbox Code Playgroud)
为什么这个函数不是static的函数shared_ptr<T>,如下所示:
template <class... Args> std::shared_ptr<T>::make(Args&&... args);
Run Code Online (Sandbox Code Playgroud)
这将使std::命名空间更加整洁,并且还允许这样的事情:
using shared_vector = std::shared_ptr<std::vector<int>>;
shared_vector a = shared_vector::make(7);
Run Code Online (Sandbox Code Playgroud) 鉴于cur_front_res和cur_back_res都是shared_ptr, std::shared_ptr 的 bool 运算符如何在表达式(即bool is_empty = cur_front_res && cur_back_res;)中触发?
仅仅因为如果操作数(即 before和 after )不是 bool 类型,&&总是会导致内置转换?&&&&
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> cur_front_res; // Empty shared_ptr
std::shared_ptr<int> cur_back_res(new int(42)); // Shared_ptr pointing to an int
bool is_empty = cur_front_res && cur_back_res;
if (is_empty) {
std::cout << "Both cur_front_res and cur_back_res are not empty" << std::endl;
} else {
std::cout << "Either cur_front_res or cur_back_res is empty" …Run Code Online (Sandbox Code Playgroud) 交换两个s的内容时shared_ptr,只交换内容。当在shared_ptr交换之前从另一个副本创建一个副本时,我很惊讶新shared_ptr副本的内容保持不变。
这是一个例子:
std::shared_ptr<int> foo (new int(10));
std::shared_ptr<int> bar (new int(20));
auto abc = foo;
std::swap (foo, bar);
std::cout << "foo: " << *foo << '\n';
std::cout << "bar: " << *bar << '\n';
std::cout << "abc: " << *abc << '\n';
Run Code Online (Sandbox Code Playgroud)
它打印:
foo: 20
bar: 10
abc: 10
Run Code Online (Sandbox Code Playgroud)
abc在这种情况下为什么不是20?鉴于它是 的副本foo。