在嵌入式环境中boost::shared_ptr的替代方案

14

我在嵌入式Linux环境中使用C++,其GCC版本为2.95

我无法使用bcp提取boost::shared_ptr文件,因为它太重了。

我想要的是一个简单的boost::shared_ptr智能指针实现,但不带有所有的boost开销(如果可能的话...)。

我可以自己编写一个版本来读取boost源代码,但我担心会漏掉一个或多个点,似乎很容易制作出错误的智能指针,而我不能承担有漏洞的实现。

那么,是否存在一个“简单”的实现或实现示例boost::shared_ptr(或任何基于引用计数的智能指针),我可以使用或作为灵感?


2
不必过于担心智能指针实现中的错误。G++ 2.95是一个有缺陷的编译器。从记忆中来看,它会对一些看起来很简单的代码进行错误编译 - 如果可能的话,我建议尝试使用3.x或4.x系列的编译器。(当然,我也理解这可能不太可能...只是要小心) - Michael Anderson
我知道它有漏洞...我必须调整我的模板代码以使其编译。我尽量保持C++代码简单,并仔细测试它。 - Nikko
5个回答

9

如果您不需要混合使用共享指针和弱指针,并且不需要自定义删除器,那么您可以使用快速且简单的my_shared_ptr:

template<class T>
class my_shared_ptr
{
    template<class U>
    friend class my_shared_ptr;
public:
    my_shared_ptr() :p(), c() {}
    explicit my_shared_ptr(T* s) :p(s), c(new unsigned(1)) {}

    my_shared_ptr(const my_shared_ptr& s) :p(s.p), c(s.c) { if(c) ++*c; }

    my_shared_ptr& operator=(const my_shared_ptr& s) 
    { if(this!=&s) { clear(); p=s.p; c=s.c; if(c) ++*c; } return *this; }

    template<class U>
    my_shared_ptr(const my_shared_ptr<U>& s) :p(s.p), c(s.c) { if(c) ++*c; }

    ~my_shared_ptr() { clear(); }

    void clear() 
    { 
        if(c)
        {
            if(*c==1) delete p; 
            if(!--*c) delete c; 
        } 
        c=0; p=0; 
    }

    T* get() const { return (c)? p: 0; }
    T* operator->() const { return get(); }
    T& operator*() const { return *get(); }

private:
    T* p;
    unsigned* c;
}

对于任何对make_my_shared<X>感兴趣的人,它可以被轻松地实现为:

template<class T, class... U>
auto make_my_shared(U&&... u)
{ 
    return my_shared_ptr<T>(new T{std::forward<U>(u)...});
}

被称为
auto pt = make_my_shared<T>( ... );

1
我看到boost中还有一个轻量级的boost::shared_ptr实现,即shared_ptr_nmt.hpp。'nmt'代表“无成员模板”。 - Nikko
1
@Virus721:“Quick and Dirty”是一个习语(http://en.wikipedia.org/wiki/Quick-and-dirty):它意味着“简单易行”用于“其所在之处”。它不能用关于内存管理、分配器、数组管理等的策略来丰富,因为它没有任何类似这样的“插头”。它清晰地完成了它的任务,但没有超出那个范围。在这个上下文中被讽刺性地使用。 - Emilio Garavaglia
1
@Valmir 编辑 - 见底部 - Emilio Garavaglia
@EmilioGaravaglia 谢谢,我会尝试这个。 - Valmir
@wavemode 是的。在 std::atomic 成为标准之前,我刚写了这个。 - Emilio Garavaglia
显示剩余8条评论

4

还有std::tr1::shared_ptr,它只是C++11标准从boost中提取的。如果允许的话,您可以选择它,或者使用引用计数编写自己的shared_ptr。


3
您关注的是哪些“boost开销”,以及shared_ptr在您的应用程序中为什么“过于沉重”?仅仅使用Boost不会产生任何开销(至少如果您只使用头文件库,例如智能指针库);我所能想到与shared_ptr相关的唯一开销是:
  • 线程安全的引用计数;由于您正在使用一个古老的编译器,我假设您也有一个古老的运行时库和内核,因此这可能非常低效。如果您的应用程序是单线程的,则可以通过#定义BOOST_DISABLE_THREADS来禁用此功能。
  • 在托管对象旁边分配引用计数结构。您可以通过使用make_shared()allocate_shared()创建对象来消除额外的分配。

在许多情况下,您可以通过不创建对象或复制共享指针来消除速度关键代码的开销-通过引用传递指针,只有在实际需要时才复制它们。

如果您需要某些指针的线程安全性,但不需要其他指针,并且(在剖析并删除所有不必要的分配和指针复制后)发现使用共享指针仍然会导致显着的开销,那么您可以考虑使用intrusive_ptr,并在对象内部管理自己的引用计数。

如果可行的话,更新到现代GNU / Linux版本也可能会有好处。自Linux 2.6引入futexes以来,线程同步效率大大提高。您可能会发现这也有其他方面的改进;在过去十年中已经进行了许多改进。更现代的编译器还将提供标准(TR1或C ++ 11)共享指针,因此您不需要Boost。


2
如果我使用bcp提取boost::shared_ptr,我会得到相当多的头文件(超过30个)和两个.cpp文件。 - Nikko
3
不需要源文件 - 我不知道它们是什么(可能是测试),但智能指针库只有头文件。只需将头文件放入您的包含路径中,并包含 boost/shared_ptr.hpp - Mike Seymour
4
头文件膨胀问题就是为什么我们公司远离boost的原因。为了使用一个简单的共享指针库,必须引入30多个头文件,这太荒谬了。而且这个例子只是个例外......大多数boost模块引入的头文件数量要比30个多得多。我不理解一个如此相互依存的架构竟然用来完成简单的事情。 - Steve
1
顺便说一句,在有人说现在的编译器速度很快,实际上很少使用到这么多头文件之前...我们关心这个头文件膨胀的原因之一是我们客户对版权问题的担忧,因此我们能够提供某种程度的赔偿。所有这些相互依存关系导致了更多不同人编写的代码。这极大地增加了某天有人可能会说我们在boost中使用的代码片段是从他们的独立作品中窃取的,并且是侵权的机会。 - Steve

3
我建议您可以单独使用shared_ptr。但是,如果您正在寻找简单的实现:
- 带有一些单元测试 - 不是线程安全的 - 自定义删除器(例如数组删除器或用于特殊资源的自定义函数对象)
请看这里:Creating a non-thread safe shared_ptr。如果您感兴趣,让我知道。

1

你可以使用shared_ptr而不需要所有的Boost开销:它是一个仅包含头文件的实现。如果你不使用其他类,只有shared_ptr会被编译。

shared_ptr的实现已经非常精简,但如果你想避免中间的引用计数块和(可能的)虚函数调用删除器函数,你可以使用boost::intrusive_ptr,它更适合嵌入式环境:它在对象本身中嵌入了一个引用计数器,你只需要提供一对增加/减少它的函数即可。缺点是你将无法使用weak_ptr

我无法评论gcc 2.95如何内联/折叠模板实例化(它是一个非常老的编译器),更近期的版本的gcc处理得相当好,所以这里你就自己看着办吧。


2
当我使用bcp提取boost::shared_ptr时,我在提取前30个包含文件后就停止了计数。 - Nikko
2
@Nikko:你为什么关心有多少个头文件?你是在尝试在一个小型嵌入式设备上构建你的项目吗? - Mike Seymour
@MikeSeymour 这是在一个需要小型二进制文件的嵌入式系统中,使用了一个不喜欢复杂模板代码的旧C++编译器。 - Nikko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接