重置方法中指向不完整的共享指针需要删除器
Shared pointer to incomplete needs deleter in reset method
我正在使用 shared_ptr 存储 C 库的指针。
这是一个包含 header bar.h:
的 C 库示例
#pragma once
typedef struct Flupp MyFlupp;
MyFlupp *
create_flupp();
void
del_flupp(MyFlupp * fp);
void
print_flupp(MyFlupp * f);
这里的结构有一个前向声明并在 bar.so 中定义。
我在我的 C++ 代码中使用 bar.so:
#include <memory>
extern "C"{
#include "bar.h"
}
int main()
{
std::shared_ptr<MyFlupp> flupp_ptr(nullptr, del_flupp);
flupp_ptr.reset(create_flupp());
print_flupp(flupp_ptr.get());
return 0;
}
这里我将 MyFlupp* 存储在 shared_ptr 中。在声明中,MyFlupp* 是未知的并设置为 nullptr。稍后我调用重置操作来设置有效指针。但是当我编译代码时,出现以下错误:
In file included from /usr/include/c++/8/bits/shared_ptr.h:52,
from /usr/include/c++/8/memory:81,
from test_foo.cpp:1:
/usr/include/c++/8/bits/shared_ptr_base.h: In instantiation of ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Yp*) [with _Yp = Flupp; <template-parameter-2-2> = void; _Tp = Flupp; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2]’:
/usr/include/c++/8/bits/shared_ptr_base.h:1293:4: required from ‘std::__shared_ptr<_Tp, _Lp>::_SafeConv<_Yp> std::__shared_ptr<_Tp, _Lp>::reset(_Yp*) [with _Yp = Flupp; _Tp = Flupp; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2; std::__shared_ptr<_Tp, _Lp>::_SafeConv<_Yp> = void]’
test_foo.cpp:10:35: required from here
/usr/include/c++/8/bits/shared_ptr_base.h:1126:19: error: invalid application of ‘sizeof’ to incomplete type ‘Flupp’
static_assert( sizeof(_Yp) > 0, "incomplete type" );
当我为重置操作提供删除器时,它正在工作。
flupp_ptr.reset(create_flupp(), del_flupp);
谁能给我解释一下这是怎么回事?我已经看过@cppreference,但没有找到答案。
问题是 Flupp
类型只被转发声明,但没有定义。在此处使用的上下文中,它被认为是不完整类型。
这对 std::shared_ptr
:
的使用有一定的影响
std::shared_ptr may be used with an incomplete type T. However, the
constructor from a raw pointer (template<class Y> shared_ptr(Y*)
) and
the template<class Y> void reset(Y*)
member function may only be
called with a pointer to a complete type (note that std::unique_ptr
may be constructed from a raw pointer to an incomplete type).
相反,您需要使用接受指针 和 删除器作为参数的相应重载。
对于 unique_ptr
,这不是必需的,因为它将自定义删除器存储为类型的一部分。但是使用 shared_ptr
删除器是类型擦除的,只能在运行时恢复。这允许您在调用 reset
时更改现有 shared_ptr
的删除器。出于这个原因,您总是需要在调用 reset
时重新声明要使用的删除器。如果没有给出删除器,每次调用 reset
也会 implicitly reset the deleter to just calling delete
on the managed pointer.
因此,要使其正常工作,只需将您的 reset
调用更改为
flupp_ptr.reset(create_flupp(), del_flupp);
我正在使用 shared_ptr 存储 C 库的指针。 这是一个包含 header bar.h:
的 C 库示例#pragma once
typedef struct Flupp MyFlupp;
MyFlupp *
create_flupp();
void
del_flupp(MyFlupp * fp);
void
print_flupp(MyFlupp * f);
这里的结构有一个前向声明并在 bar.so 中定义。 我在我的 C++ 代码中使用 bar.so:
#include <memory>
extern "C"{
#include "bar.h"
}
int main()
{
std::shared_ptr<MyFlupp> flupp_ptr(nullptr, del_flupp);
flupp_ptr.reset(create_flupp());
print_flupp(flupp_ptr.get());
return 0;
}
这里我将 MyFlupp* 存储在 shared_ptr 中。在声明中,MyFlupp* 是未知的并设置为 nullptr。稍后我调用重置操作来设置有效指针。但是当我编译代码时,出现以下错误:
In file included from /usr/include/c++/8/bits/shared_ptr.h:52,
from /usr/include/c++/8/memory:81,
from test_foo.cpp:1:
/usr/include/c++/8/bits/shared_ptr_base.h: In instantiation of ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Yp*) [with _Yp = Flupp; <template-parameter-2-2> = void; _Tp = Flupp; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2]’:
/usr/include/c++/8/bits/shared_ptr_base.h:1293:4: required from ‘std::__shared_ptr<_Tp, _Lp>::_SafeConv<_Yp> std::__shared_ptr<_Tp, _Lp>::reset(_Yp*) [with _Yp = Flupp; _Tp = Flupp; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2; std::__shared_ptr<_Tp, _Lp>::_SafeConv<_Yp> = void]’
test_foo.cpp:10:35: required from here
/usr/include/c++/8/bits/shared_ptr_base.h:1126:19: error: invalid application of ‘sizeof’ to incomplete type ‘Flupp’
static_assert( sizeof(_Yp) > 0, "incomplete type" );
当我为重置操作提供删除器时,它正在工作。
flupp_ptr.reset(create_flupp(), del_flupp);
谁能给我解释一下这是怎么回事?我已经看过@cppreference,但没有找到答案。
问题是 Flupp
类型只被转发声明,但没有定义。在此处使用的上下文中,它被认为是不完整类型。
这对 std::shared_ptr
:
std::shared_ptr may be used with an incomplete type T. However, the constructor from a raw pointer (
template<class Y> shared_ptr(Y*)
) and thetemplate<class Y> void reset(Y*)
member function may only be called with a pointer to a complete type (note that std::unique_ptr may be constructed from a raw pointer to an incomplete type).
相反,您需要使用接受指针 和 删除器作为参数的相应重载。
对于 unique_ptr
,这不是必需的,因为它将自定义删除器存储为类型的一部分。但是使用 shared_ptr
删除器是类型擦除的,只能在运行时恢复。这允许您在调用 reset
时更改现有 shared_ptr
的删除器。出于这个原因,您总是需要在调用 reset
时重新声明要使用的删除器。如果没有给出删除器,每次调用 reset
也会 implicitly reset the deleter to just calling delete
on the managed pointer.
因此,要使其正常工作,只需将您的 reset
调用更改为
flupp_ptr.reset(create_flupp(), del_flupp);