无符号字符数组的自动指针?

3

我需要一个类似于std::auto_ptr的类来管理一个使用new[]分配的unsigned char*数组。但是auto_ptr只会调用delete而不是delete[],所以我不能使用它。

我还需要一个函数来创建并返回该数组。我自己实现了一个名为ArrayDeleter的类,在这个例子中我使用它:

#include <Utils/ArrayDeleter.hxx>

typedef Utils::ArrayDeleter<unsigned char> Bytes;

void f()
{
  // Create array with new
  unsigned char* xBytes = new unsigned char[10];
  // pass array to constructor of ArrayDeleter and
  // wrap it into auto_ptr
  return std::auto_ptr<Bytes>(new Bytes(xBytes));
}

...
// usage of return value
{
  auto_ptr<Bytes> xBytes(f());
}// unsigned char* is destroyed with delete[] in destructor of ArrayDeleter

有没有更优雅的解决方法?(甚至使用另一个“流行”的库)
4个回答

11

Boost有多种自动指针,包括用于数组的指针。你考虑过std::vector是否足够吗?向量在内存中保证是连续的,如果你知道大小并通过reserve()resize()提前分配内存,那么内存中的位置不会改变。


我看了一下boost,我认为scoped_array可以胜任。谢谢。 - Gianluca
3
为什么你不使用向量? - GManNickG
@GMan: 当然,现在我明白这是一个更好的想法。谢谢 - Gianluca

3
我需要调用一个以unsigned char*为参数的方法。
std::vector<unsigned char> vec;
.
.
.
legacy_function(&vec[0], vec.size());

2

使用 std::basic_string<unsigned char> 怎么样?或者是 std::vector<unsigned char>


我随后必须调用一个以unsigned char*为参数的方法。有没有一种方法可以从您建议的容器中的其中一个内部访问它?basic_string的data()方法可以吗? - Gianluca
你可以使用std::string的'.c_str()'方法,它会返回一个以null结尾的char*。 - Konrad

-1
  1. 你所说的是一个 int 数组,而不是具有析构函数的复杂 C++ 类型。对于这样的数组,调用 delete[] 等同于调用 delete。因此使用 std::auto_ptr 没有问题。

  2. 我认为你提出的方法非常野蛮。实际上,你分配了两次内存:一次是为所需的数组分配内存,然后你还分配了一个 ArrayDeleter 实例,它封装了分配的数组的指针。

这种方法的缺点有:

  • 性能较差。堆操作很重,而且具有显著的内存开销。
  • 访问速度较慢。通过std::auto_ptr<Bytes>访问数组元素时,编译器将生成两个间接引用:一个用于获取Bytes对象,另一个用于访问元素。 简单来说:std::auto_ptr具有指向Bytes对象的指针,该对象具有指向数组的指针。
  • 错误/异常一致性较差。想象一下,如果operator new无法分配Bytes对象,它将生成一个异常,可以处理该异常。但此时您已经分配了数组。这个分配将会丢失。

我会执行以下操作之一:

  1. 如果你谈论的是普通类型 - 只需使用 std::auto_ptr<type>。这应该可以完成工作。但是,您应该使用编译器进行检查。

  2. 对于复杂类型:您可以创建自己的包装器,而不是使用 std::auto_ptr

  3. 另一种变体:类似于您所做的。但是,您应该摆脱额外的内存分配和间接引用。

2
在动态分配的数组上调用delete始终是未定义行为,即使在您尝试的所有编译器上它似乎总是有效。 - fredoverflow
delete[] 不等同于调用 delete,即使对于 POD 也是如此。请参阅标准中的 18.6.1.2(数组形式):“void operator delete[](void* ptr) throw(); ... 要求:ptr ... 必须是先前调用 operator new 或 operator new[](std::size_t,const std::nothrow_t&) 返回的值。” - Francesco
这正是我写下“你应该用你的编译器检查它”的原因。 严格来说,你是正确的。标准规定这是未定义行为。另一方面,我说了实际上会发生什么。至少在MSVC编译器上是这样。之所以应该使用“delete[]”而不是“delete”,并不是因为我们需要知道需要释放多少内存 - 根据这个论点,你也必须将内存大小传递给“free”函数。 原因是当你使用“delete[]”时,编译器除了释放内存外,还会生成对象的d'tors调用。 - valdo
1
@valdo:但人们想要编写C++,而不是它的特定变体。依赖未定义的行为是不好的。 - GManNickG
@Valdo,那不是真的:当你使用delete[]时,你以正确的形式释放了正确数量的内存。为什么你建议依赖(某个版本的)编译器的古怪行为,我不知道。 - Francesco

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