【问题标题】:How to use std::vector for classes with handles如何将 std::vector 用于带句柄的类
【发布时间】:2019-05-22 09:29:34
【问题描述】:

我已经定义了以下类,女巫创建并释放一个不透明的对象(例如操作系统句柄)

class A
{
public:

    A(...)
    {
        allocateHandle(&h);
    }

    ~A()
    {
        freeHandle(h);
    }

    SomeHandle h;
}

在创建和调整 A 的 std::vector 大小时,程序崩溃。

std::vector<A> vec;
vec.reserve(2);

vec.emplace_back(...);
vec.emplace_back(...);
vec.emplace_back(...); //crash

当 std::vector 重新分配内存时,它会调用所有对象的移动构造函数,从而也移动 A 中的句柄(基本上是一个整数)。

但是,它也调用了旧对象的析构函数,调用freeHandle(),因此它释放了句柄后面的内存,新对象仍然拥有,这变得无效并导致崩溃。

我应该如何实现move-constructor,这样新创建的对象在删除旧对象时不会变得无效?

【问题讨论】:

    标签: c++ c++11 vector move-constructor


    【解决方案1】:

    您需要为您的对象添加一些“没有有效的句柄持有”状态。如果您的 SomeHandle 已经有一个“无效句柄”值(通常使用 0),您可以使用它:

    class A
    {
    public:
    
        A(...)
        {
            allocateHandle(&h);
        }
    
        A(A &&src) : h(src.h)
        {
            src.h = INVALID;
        }
    
        A& operator= (A &&rhs)
        {
          if (this == &rhs) return *this;
          if (h != INVALID) freeHandle(h);
          h = rhs.h;
          rhs.h = INVALID;
          return *this;
        }
    
        ~A()
        {
            if (h != INVALID)
              freeHandle(h);
        }
    
        SomeHandle h;
    }
    

    如果没有“无效句柄”值,可以将h的类型改为std::optional&lt;SomeHandle&gt;,并使用std::nullopt作为无效值。

    【讨论】:

    • 一般来说,如果 C++17 可用,我会建议 optional,因为它可以节省大量样板文件
    • @bartop 它如何保存样板文件? move-from 可选仍然包含一个 (moved-from) 值,如果 SomeHandle 真的只是一个 int(很常见),它根本不会失效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-03
    • 1970-01-01
    • 2016-03-31
    • 2019-10-12
    • 2019-07-17
    • 2011-01-21
    • 2020-12-07
    相关资源
    最近更新 更多