Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否共享ptr';s数据或要求使用;删除者;?_C++_C++11_Shared Ptr_Language Lawyer - Fatal编程技术网

C++ 是否共享ptr';s数据或要求使用;删除者;?

C++ 是否共享ptr';s数据或要求使用;删除者;?,c++,c++11,shared-ptr,language-lawyer,C++,C++11,Shared Ptr,Language Lawyer,您可以使用shared\u ptr来存储指向不完整类型的指针,只要在构建shared\u ptr的过程中可以删除该指针(具有定义良好的行为)。例如,PIMPL技术: struct interface { interface(); // out-of-line definition required ~interface() = default; // public inline member, even if implicitly define

您可以使用
shared\u ptr
来存储指向不完整类型的指针,只要在构建
shared\u ptr
的过程中可以删除该指针(具有定义良好的行为)。例如,PIMPL技术:

struct interface
{
    interface();                 // out-of-line definition required
    ~interface() = default;   // public inline member, even if implicitly defined
    void foo();
private:
    struct impl;                 // incomplete type
    std::shared_ptr<impl> pimpl; // pointer to incomplete type
};
[interface.cpp]

struct interface::impl
{
    void foo()
    {
        std::cout << "woof!\n";
    }
};

interface::interface()
    : pimpl( new impl ) // `delete impl` is well-formed at this point
{}

void interface::foo()
{
    pimpl->foo();
}
3要求:
p
应为 可转换为
T*
<代码>Y应为完整类型。表达式
delete p
应具有良好的结构、明确的行为,且不得 抛出异常

4效果:构造一个拥有 指针
p

5个后置条件:
使用计数()==1&&get()==p

6抛出:
bad\u alloc
,或在 无法获取内存以外的资源

注意:对于此ctor,
shared_ptr
不需要拥有删除器。对于删除器,标准似乎是指自定义删除器,例如您在构建过程中作为附加参数提供的删除器(或
共享的\u ptr
从另一个
共享的\u ptr
,例如通过副本分配)。另请参见(另请参见[util.smartptr.shared.const]/9)。实现(boost、libstdc++、MSVC,我猜每个sane实现)总是存储一个“所有者对象”

由于删除器是自定义删除器,
shared_ptr
的析构函数是根据
delete
(删除表达式)定义的,如果没有自定义删除器:

[util.smartptr.shared.dest]

1影响:

  • 如果
    *此
    为空或与共享所有权 另一个
    shared\u ptr
    实例(
    use\u count()>1
    ),没有边 效果
  • 否则,如果该
    *拥有一个对象
    p
    和一个删除者
    d
    d(p)
    被称为
  • 否则,
    *此
    拥有一个指针
    p
    ,并且
    delete p
    是 打电话来
我假设其目的是,即使在
shared\u ptr
dtor的范围内,delete表达式格式错误或将调用UB,也需要一个实现来正确删除存储的指针。(delete表达式必须格式良好,并且在ctor中具有定义良好的行为。)因此,问题是

问题:哪里需要这个?

(或者我是不是太挑剔了,而且很明显实现需要使用“所有者对象”?)

问题:哪里需要这个?

如果不需要,析构函数将具有未定义的行为,并且标准没有要求未定义行为的习惯:-)

如果满足构造函数的先决条件,则析构函数将不会调用未定义的行为。实现如何确保这一点尚未明确,但您可以假设它是正确的,您不需要知道如何确保。如果不希望实现做正确的事情,那么析构函数将有一个先决条件

(或者我是不是太挑剔了,而且很明显实现需要使用“所有者对象”?)

是的,必须创建一些额外的对象来拥有指针,因为引用计数(或其他簿记数据)必须在堆上,而不是任何特定
共享\u ptr
实例的一部分,因为它可能需要超出任何特定实例。是的,有一个额外的对象,它拥有指针,你可以称之为所有者对象。如果用户没有提供删除器,那么所有者对象只调用
delete
。例如:

template<typename T>
struct SpOwner {
  long count;
  long weak_count;
  T* ptr;
  virtual void dispose() { delete ptr; }
  // ...
};

template<typename T, typename Del>
struct SpOwnerWithDeleter : SpOwner<T> {
  Del del;
  virtual void dispose() { del(this->ptr); }
  // ...
};
模板
结构所有者{
长计数;
长弱_计数;
T*ptr;
虚拟void dispose(){delete ptr;}
// ...
};
模板
结构SpOwnerWithDeleter:SpOwner{
德尔德尔;
虚拟void dispose(){del(this->ptr);}
// ...
};

现在一个
shared\u ptr
有一个
SpOwner*
,当计数降到零时,它调用虚拟函数
dispose()
,该函数调用
delete
或调用deleter,具体取决于对象的构造方式。当构建
共享的ptr
时,决定是构建
SpOwner
还是构建
SpOwnerWithDeleter
,并且当
共享的ptr
被销毁时,该类型仍然相同,因此,如果它需要处理所拥有的指针,那么它将做正确的事情。

SpOwner
是一个deleter对象,因为它定义了删除策略。它不同于作为参数传递的deleter,因为它不是函子。”然后键入拥有指针的已擦除对象,只调用delete“这就是我所说的“deleter对象”。在libstdc++中:
\u Sp\u counted\u ptr
存储在
\u shared\u count
中的
\u shared\u ptr
中(作为指针存储在堆上),该对象由
shared\u ptr
派生而来。但它不是
get\u deleter
返回的,因此它不是
shared\u ptr
使用的“deleter对象”。我用引号引这些词是有原因的。owner对象不“存储删除器对象”(正如您在问题中所说的那样),而是自行删除。我更改了问题中的术语,也许现在更清楚了?好吧,那么您的问题基本上是“是否有什么东西负责安全地删除指针?”答案是“是的,当然”:-)但不需要指定如何完成。必须创建一些其他对象来存储堆上的引用计数,因为它们不能在任何单个
共享\u ptr
对象中,并且当指针的动态类型已知时,该其他对象必须由构造函数创建,以便它(或它创建的对象)知道如何安全地删除指针。实现者必须非常不称职才能不这样做
template<class Y> explicit shared_ptr(Y* p);
~shared_ptr();
template<typename T>
struct SpOwner {
  long count;
  long weak_count;
  T* ptr;
  virtual void dispose() { delete ptr; }
  // ...
};

template<typename T, typename Del>
struct SpOwnerWithDeleter : SpOwner<T> {
  Del del;
  virtual void dispose() { del(this->ptr); }
  // ...
};