用C ++包装char *的最佳方法?

时间:2019-04-22 17:36:27

标签: c++ c++11

在我的代码中,我使用当前以这种方式分配的缓冲区:

char* buf1 = (char*)malloc(size);

但是,在代码中的某些点上,我想将指针重新分配给内存中的其他位置。问题是代码中还有其他地方仍需要访问指针buf1。

用C ++做到这一点的最佳方法是什么?现在,我正在考虑编写一个带有单个char *的结构,然后分配该结构类型的对象并将其传递到需要的地方,并引用包装后的指针以获取buf1的当前值。

但是,这似乎与unique_ptr相似。如果我使用unique_ptr,如何将char *包装起来?我对此进行测试时遇到了一些麻烦,但不确定它是否受支持。

为了澄清:这些缓冲区是大小不同的字节。

1 个答案:

答案 0 :(得分:3)

通常,此问题无法回答。数组char可能想做的事情太多了。在不知道您实际想要做什么的情况下,无法说出可能使用的好的抽象方法……

如果您想使用字符串做东西,只需使用std::string。如果您希望动态大小的缓冲区可以增长和缩小,请使用std::vector

如果您只需要一个字节缓冲区,该缓冲区的大小在运行时确定,或者通常只想在动态存储中使用,我将使用std::unique_ptr。尽管std::unique_ptr<T>仅用于单个对象,但部分特殊化std::unique_ptr<T[]>可用于处理动态分配的数组。例如:

auto buffer = std::unique_ptr<char[]> { new char[size] };

通常,建议通过new创建对象并获得std::unique_ptr的方法是使用std::make_unique。而且,如果要将缓冲区初始化为某个特定值,则确实应该使用std::make_unique<char[]>(value)。但是,std::make_unique<T[]>()将对它创建的数组的元素进行值初始化。对于char数组,这实际上意味着您的数组将被零初始化。以我的经验,不幸的是,即使整个缓冲区在创建后立即被覆盖,编译器也无法优化零初始化。因此,如果为了避免初始化的开销而需要一个未初始化的缓冲区,则不能使用std::make_unique。理想情况下,您只需定义自己的函数即可通过new创建一个默认初始化的数组,并为其获取一个std::unique_ptr,例如:

template <typename T>
inline std::enable_if_t<std::is_array_v<T> && (std::extent_v<T> == 0), std::unique_ptr<T>> make_unique_default(std::size_t size)
{
    return std::unique_ptr<T> { new std::remove_extent_t<T>[size] };
}

然后

auto buffer = make_unique_default<char[]>(new char[size]);

似乎C ++ 20将以std::make_unique_default_init的形式包含此功能。因此,那将是首选方法。

请注意,如果要处理普通std::unique_ptr,则仍然必须分别传递缓冲区的大小。如果您打算绕过缓冲区,则可能需要捆绑std::unique_ptrstd::size_t

template <typename T>
struct buffer_t
{
    std::unique_ptr<T[]> data;
    std::size_t size;
};

请注意,类似于上面struct的内容表示缓冲区的所有权。因此,例如在从工厂函数返回新缓冲区时,例如,

buffer_t makeMeABuffer();

或将缓冲区的所有权移交给其他人,例如

DataSink(buffer_t&& buffer)

您不希望使用它只是将某些功能指向缓冲区数据,并且大小可以在不转移所有权的情况下进行一些处理。为此,您只需传递一个指针和大小,或者例如使用span(从C ++ 20开始;也可以作为GSL的一部分使用)…