gpt4 book ai didi

c++ - 具有类型删除析构函数的 unique_ptr 不太有效(有警告)

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:08:30 24 4
gpt4 key购买 nike

有一个不错的小技巧here允许使用 std::unique_ptr不完整的类型。

相关代码如下:

// File: erasedptr.h
#include <memory>
#include <functional>

// type erased deletor (an implementation type using "veneer")
template <typename T>
struct ErasedDeleter : std::function<void(T*)>
{
ErasedDeleter()
: std::function<void(T*)>( [](T * p) {delete p;} )
{}
};

// A unique_ptr typedef
template <typename T>
using ErasedPtr = std::unique_ptr<T, ErasedDeleter<T>>;


// Declare stuff with an incomplete type
struct Foo;
ErasedPtr<Foo> makeFoo();


// File: main.cpp (Foo's definition is not available in this translation unit)
#include "erasedptr.h"
int main() {
ErasedPtr<Foo> f; // [R1]
f = makeFoo();
// ~Foo() gets called fine
}

// File: foo.cpp
#include <iostream>
#include "erasedptr.h"
struct Foo {
~Foo() { std::cout << "~Foo()\n" ; }
};
ErasedPtr<Foo> makeFoo() { return ErasedPtr<Foo>(new Foo); }

这适用于我尝试过的所有编译器:gcc 4.9、clang 3.5 以及 msvc VS13 和 VS15。但它们都会产生以下警告:

 deletion of pointer to incomplete type 'Foo'; no destructor called

如果上面的 [R1] 被替换为 ErasedPtr<Foo> f( makeFoo() ); ,警告不会出现。

最后,析构函数确实 被调用并且似乎没有实际问题。该警告是有问题的,因为在质量关键环境中不能忽略它,并且这种非常有用的模式不可用。

要复制,请创建 3 个文件 erasedptr.hpp , main.cpp , foo.cpp如上所述并编译。

所以问题是:这是怎么回事?是否可以有任何替代实现来规避此警告?

最佳答案

你的问题是有效的,但你尝试使用的代码有点复杂,所以让我停下来找到想要的解决方案。

  • 您在这里所做的不是类型删除(Andrzej 对此也错了)- 您只是将删除捕获到运行时函数值中,顺便说一句,没有任何好处。类型删除 OTH 是指其他代码部分丢失有关初始类型的信息。
  • 我在 VS 2015 上试过你的代码,它也调用析构函数 ~Foo(),但这只是运气好,这意味着编译器正在做一些奇特的事情。如果您不使用 std::function 而是编写自己的自定义删除器,则不会调用析构函数。

方案一——类型删除

如果您真的想删除类型,您可以按以下方式编写/使用 ErasedPtr:

erasedptr.h

// file erasedptr.h

#include <memory>
#include <functional>

// make type erased deleter
template <typename T>
std::function<void(void*)> makeErasedDeleter()
{
return {
[](void* p) {
delete static_cast<T*>(p);
}
};
};

// A unique_ptr typedef
template <typename T>
using ErasedPtr = std::unique_ptr<T, std::function<void(void*)>>;

foo.cpp

// file foo.cpp

#include <iostream>
#include "erasedptr.h."

struct Foo {
~Foo() { std::cout << "~Foo()\n" ; }
};

// capture creation and deletion of Foo in this translation unit
ErasedPtr<Foo> makeFoo() {
return { new Foo, makeErasedDeleter<Foo>() };
}

main.cpp

// file main.cpp (Foo's definition is not available in this translation unit)

#include "erasedptr.h"

// fwd decl Foo
struct Foo;
ErasedPtr<Foo> makeFoo();

int main() {
ErasedPtr<Foo> f; // [R1]
f = makeFoo();
// ~Foo() gets called fine
}

这样只有 foo.cpp 需要知道实际类型并将删除捕获到 std::function 中。

解决方案 2 - 不完整的类型,真的

您真正想要的是处理不完整的类型。 STL 的默认删除器 std::default_delete 存在的“问题”是它在编译时断言删除是否安全——这该死的是对的!

要使其正常工作,就是使用显式模板实例化告诉编译器/链接器您实际上关心删除的正确实现。这样你就不需要任何特殊的 typedef/template 别名作为你的唯一指针:

foo.cpp

// file foo.cpp

#include "foo_fwddecl.h"

// capture creation of Foo in this translation unit
std::unique_ptr<Foo> makeFoo() {
return std::make_unique<Foo>();
}

// explicitly instantiate deletion of Foo in this translation unit
template void std::default_delete<Foo>::operator()(Foo*) const noexcept;
template void std::default_delete<const Foo>::operator()(const Foo*) const noexcept;
// note: possibly instantiate for volatile/const volatile modifiers

foo_fwddecl.h

#include <memory>

struct Foo;

std::unique_ptr<Foo> makeFoo();

extern template void std::default_delete<Foo>::operator()(Foo*) const noexcept;
extern template void std::default_delete<const Foo>::operator()(const Foo*) const noexcept;
// note: possibly instantiate for volatile/const volatile modifiers

main.cpp

// file main.cpp (Foo's definition is not available in this translation unit)

#include "foo_fwddecl.h"

int main() {
std::unique_ptr<Foo> f; // [R1]
f = makeFoo();
// ~Foo() gets called fine
}

关于c++ - 具有类型删除析构函数的 unique_ptr 不太有效(有警告),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35929654/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com