想要实现 C++ 管理一段内存块

2018-12-04 12:58:33 +08:00
 yuikns

如下是一个简单的 c++ class。目标是作为一个容器管理一段连续的内存,并且可以简单别太浪费,不要内存泄漏地被 copy/move。

水平太菜自觉考虑难以周全,所以想要求 v 友们指教下代码还有哪些 bug。

无论是本身的指点,还是更好的实现思路的指教都非常感谢。


typedef uint8_t byte;

class Bytes {
 public:
  Bytes() noexcept : data_(nullptr), size_(0) {}

  // 给定 string, 读取数据后保存
  explicit Bytes(const string& data) noexcept
      : Bytes(reinterpret_cast<const byte*>(data.data()), data.size()) {}

  
  explicit Bytes(const byte* bytes, size_t size) noexcept {
    assign(bytes, size);
  }

  Bytes(const Bytes& rhs) noexcept : data_(rhs.data_), size_(rhs.size_) {}

  Bytes(const Bytes&& rhs) noexcept
      : data_(std::move(rhs.data_)), size_(rhs.size_) {}

  virtual ~Bytes() {}

  const size_t size() const noexcept { return size_; }

  const std::shared_ptr<byte> data() const noexcept { return data_; }

  // return is empty
  const bool Empty() const noexcept {
    return data_.get() == nullptr || size() == 0;
  }

  string String() const noexcept {
    return data_.get() == nullptr
               ? string()
               : string(reinterpret_cast<const char*>(data_.get()), size());
  }

  string HexString() const noexcept {
    size_t n = size_;
    char* cout = new char[n * 2];
    const char* rune = "0123456789abcdef";
    for (size_t i = 0; i < n; i++) {
      byte uc = data_.get()[i];
      // little-endian
      cout[2 * i] = rune[uc >> 4];
      cout[2 * i + 1] = rune[uc & 0xf];
    }
    string out(cout, n * 2);
    delete[] cout;
    return out;
  }

  int Compare(const Bytes& that) const noexcept {
    size_t sz = size();
    size_t that_sz = that.size();
    size_t min_sz = (sz < that_sz) ? sz : that_sz;
    int r = memcmp(data().get(), that.data().get(), min_sz);
    return r != 0 ? r : (sz == that_sz ? 0 : (sz < that_sz ? -1 : +1));
  }

  // Return the nth byte in the referenced data.
  // Didn't check: n < size
  byte& operator[](size_t n) noexcept {  //
    return data_.get()[n];
  }

  std::shared_ptr<byte> Resize(size_t size) noexcept {
    std::shared_ptr<byte> new_data(new byte[size],
                                   std::default_delete<byte[]>());
    memset(new_data.get(), 0, size);
    if (this->data_.get() != nullptr) {
      size_t min_sz = (size < this->size_) ? size : this->size_;
      memcpy(static_cast<byte*>(new_data.get()),
             static_cast<const byte*>(this->data_.get()), min_sz);
    }
    this->data_.swap(new_data);
    this->size_ = size;
    return this->data_;
  }

  static Bytes ConcatBytes(const vector<Bytes>& v) noexcept {
    Bytes bytes;
    size_t sz = 0;
    for (auto i : v) {
      sz += i.size();
    }
    bytes.Resize(sz);
    size_t off = 0;
    for (auto i : v) {
      bytes.writeTo(i.data_.get(), off, i.size());
      off += i.size();
    }
    return bytes;
  }

 private:
  std::shared_ptr<byte> data_;
  size_t size_;

  void clear() noexcept {
    data_.reset();
    size_ = 0;
  }

  void writeTo(const byte* bytes, size_t offset, size_t size) noexcept {
    memcpy(data_.get() + offset,  //
           static_cast<const byte*>(bytes), size);
  }

  void assign(const byte* bytes, size_t size) noexcept {
    std::shared_ptr<byte> new_data(new byte[size],
                                   std::default_delete<byte[]>());
    memcpy(static_cast<byte*>(new_data.get()), static_cast<const byte*>(bytes),
           size);
    size_ = size;
    data_.swap(new_data);
  }
};

3424 次点击
所在节点    C
26 条回复
wutiantong
2018-12-04 17:20:36 +08:00
nmgwddj
2018-12-04 19:20:17 +08:00
世界上最痛苦的事情就是在用 C++ 还要自己管理内存!
exonuclease
2018-12-04 19:42:38 +08:00
拷贝构造函数只是复制指针?这个设计有问题吧。我觉得既然提供了移动构造函数 拷贝构造函数就应该实现成拷贝数据了
yuikns
2018-12-05 02:15:47 +08:00
@wutiantong 👍


@exonuclease 我也觉得语义和约定的不一样。因为想要一个构造完毕后就不再动的结构,因此深拷贝并不需要。发现很多工程以及 stl 里面设计都是直接类似结构的 copy 置为 delete,菜鸟不懂啦,我一般是直接照着这种设计做,并不知其所以然。但有的时候我就想了,为什么一定要自己再写个指针呢?能不能更简单点过去呢?所以才贴了如上例子。
exonuclease
2018-12-05 09:38:33 +08:00
@yuikns stl 通常要么不允许拷贝 要么就实现成值语义的 我觉得倒是比别的语言里面那种到处引用来引用去的符合直觉 也更安全 别的语言那么搞是为了性能 c++可以移动构造 填了一些性能的坑 你用了 shared_ptr 的话 实现成这样其实也是安全的 就是不符合大家写 c++的习惯
Mirana
2018-12-05 12:17:56 +08:00
没看懂这是个啥,还以为是 allocator

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/514171

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX