【问题标题】:Smart pointers to within a smart-pointer managed array指向智能指针托管数组中的智能指针
【发布时间】:2016-10-09 12:58:30
【问题描述】:

我正在围绕存储在字符数组中的低级对象编写 C++ 包装器。我希望能够使用智能指针来管理我的班级的生命周期。我班的几个成员需要返回指向对象的指针;因为这些不是单独的分配,所以我不能为它们使用标准的智能指针,一旦主对象被释放,这些指针将变得无效。

为了具体起见,考虑以下简单的字符串类:

class 
String
{
    char* s;
    size_t len;

protected:
    String(const char* str) {
        len = std::strlen(str);
        s = new char[len];
        std::strcpy(s, str);
    }
public:
    ~String() {
        delete s;
    }

    char*
    getString() {
        return s;
    }

    char*
    getSubstr(size_t idx) {
        if (idx < len)
            return &s[idx];
        else
            return nullptr;
    }

    static std::shared_ptr<String>
    makeString(const char* str) {
        return std::shared_ptr<String>(new String(str));
    }
};

我可以使用std::shared_ptr 管理String 的实例。但是当我的String 对象被破坏时,getString()getSubstring() 返回的任何指针都将无效。我希望getString()getSubstring() 返回某种智能指针,该指针将持有对父对象的引用,因此以下代码有效:

std::shared_ptr<String> str = String::makeString("Hello world");
SOMETHING<char> substr = str->getSubstr(6);

std::printf("String: %s\n", str->getString());
str.reset();
std::printf("Substring: %s\n", substr.get());

有什么方法可以使用标准 C++ 功能实现这一点?如果没有,那么 Boost 呢?

更新

根据 Yakk 的建议,这是一个似乎可以工作的版本(使用 gcc 或 clang 编译为 C++11 时):

#include <cstring>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>

using boost::shared_ptr;
using boost::enable_shared_from_this;

class 
String : public enable_shared_from_this<String>
{
    size_t len;
    char* s;

protected:
    String(const char* str) : len(std::strlen(str)), s(new char[len]) {
        std::copy(str, str+len, s);
    }
public:
    ~String() {
        delete s;
    }

    shared_ptr<char[]>
    getString() {
        return shared_ptr<char[]>(shared_from_this(), s);
    }

    shared_ptr<char[]>
    getSubstr(size_t idx) {
        if (idx < len)
            return shared_ptr<char[]>(shared_from_this(), s+idx);
        else
            return shared_ptr<char[]>();
    }

    static shared_ptr<String>
    makeString(const char* str) {
         return shared_ptr<String>(new String(str));
    }
};

【问题讨论】:

    标签: c++ c++11 smart-pointers


    【解决方案1】:

    您可能需要shared_ptr“别名”构造函数。

    如果你支持 C++1z,你甚至会得到[]

    您的“某事”只是shared_ptr

    std::shared_ptr<char>
    getSubstr(size_t idx) {
        if (idx < len)
            return {shared_from_this(), &s[idx]};
        else
            return {};
    }
    

    并将enable_shared_from_this 添加到String

    或者,直接通过shared_ptr 中的String 管理缓冲区:

    std::shared_ptr<char> s;
    

    String(const char* str) {
        len = std::strlen(str);
        s = std::shared_ptr<char>(new char[len], std::default_deleter<char[]>{});
        std::strcpy(s.get(), str);
    }
    
    std::shared_ptr<char>
    getSubstr(size_t idx) {
        if (idx < len)
            return {s, s.get()+idx};
        else
            return {};
    }
    

    这种策略的优点是String 不需要由共享ptr 管理——您可以将它粘贴在向量中或在堆栈上声明它。 C++ 在这样的常规类型上蓬勃发展。

    同时内部缓冲区由智能指针管理,因此子字符串不能悬空。

    这个的核心是别名构造函数。共享指针有 2 个组成部分:引用计数块和数据指针。

    引用计数块有强计数、弱计数和销毁功能。

    别名构造函数允许您使用不同的共享指针的引用计数块和任意数据指针。这旨在将共享指针返回给由共享指针管理的类的成员,这基本上就是您正在做的事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-06
      • 1970-01-01
      • 2014-03-04
      • 2017-04-29
      • 1970-01-01
      • 1970-01-01
      • 2016-09-17
      • 2021-11-28
      相关资源
      最近更新 更多