std :: auto_ptr的最佳实践

时间:2010-12-10 22:58:07

标签: c++ smart-pointers

我只是习惯使用std :: auto_ptr的智能指针。

假设我想用auto_ptr和普通指针调用一个函数。

auto_ptr<uint32> data_smart(new uint32[123])]);
uint32 data_fix[123];
uint32* data_dumb = new uint32[123];

processData(data_smart);
processData(data_fix);
processData(data_dumb);

没有超载的最佳做法是什么?使用带有uint32 *参数的processData函数?我可以使用.get()将智能指针强制转换为uint32 *吗?或者我应该怎么做? 提前谢谢!

8 个答案:

答案 0 :(得分:5)

1

auto_ptr<uint32> data_smart(new uint32[123])]);

不要那样做。 auto_ptr仅适用于标量(它会调用delete而不是delete[])。

2。  auto_ptr拥有它指向的对象,因此除非你想将所有权传递给该函数(在你的代码中没有),该函数应该接受一个普通的指针。因此,您应该将呼叫更改为:

processData(data_smart.get());

为了明确表示data_smart继续拥有该对象。

答案 1 :(得分:1)

编辑:Noah Roberts对你的问题的评论在这里是一个更大的问题,但即使示例代码错误,这也回答了问题....


  

......没有超载......

如果你想在没有重载的情况下做到这一点,唯一适用于所有这些的选项就是让方法采用哑指针参数。

  

对于这种情况,我可以将智能指针强制转换为uint32 *吗?

没有。使用std::auto_ptr<t>::get()

答案 2 :(得分:1)

首先,不要使用指向数组的指针初始化auto_ptr。它不受支持,最终会导致内存泄漏。 std :: auto_ptr只处理单个对象。

如果您仍想使用std :: auto_ptr,但仅对于单个对象,则需要记住std :: auto_ptr在复制构造函数中传输所有权。这意味着如果按值传递data_smart,则在调用processData后,本地auto_ptr(data_smart)将不会保留任何内存。

最后,你可能想使用boost :: scoped_array或boost :: shared_array。

答案 3 :(得分:1)

最佳做法是不使用auto_ptr。它将在C ++ 0x中弃用,并替换为std::unique_ptr(参考:C ++ 0x草案标准,附录D,第10段)。与此同时,替代方案包括std::tr1::shared_ptrboost::scoped_ptr

但是你的例子是一个数组,那些指针类型对于数组来说不是。您可以使用boost::shared_array

但是标准本身没有数组智能指针。这可能是因为他们认为您应该使用std::vector代替(或std::array用于固定大小的数组,当您在编译时知道大小时)。鉴于此,您可以执行以下操作:

std::vector<uint32> dataVector;
data.reserve(123);

// or, if the size is always 123:
std::tr1::array<uint32, 123> dataArray;

现在,您可以调用接受常规普通版uint32*的函数,因为vectorstd::tr1::array都有方法可以将数据作为指针访问一个C风格的数组:

processData(&dataVector[0]);
processData(dataArray.data());

如果您打算这样做,我会强烈建议添加边界检查。将第二个参数传递给processData,其大小为数组:

processData(&dataVector[0], dataVector.size());

如果您可以完全放弃C风格的指针/数组,更好的方法可能是通过引用传递:

void processData(std::vector<uint32>& data) {
    // process the data
}

// call it like this:
processData(dataVector);

但这仅适用于vector s,而不适用于std::tr1::array s或任何其他容器。因此,更进一步,您可以使用接受迭代器的模板:

template <class AnIterator>
void processData(AnIterator begin, AnIterator end) {
    for (AnIterator it = begin; it != end; ++it) {
        // process each item
    }
}

// call it like this
processData(dataVector.begin(), dataVector,end());

// or like this
processData(dataArray.begin(), dataArray.end());

// or even like this (assume c_data is a C-style array):
processData(c_data, c_data + number_of_items_in_c_data);

最后一个可行,因为指向C风格数组的指针可以用作迭代器。

答案 4 :(得分:0)

为什么你不应该使用auto和dumb(如你所说)将相同数据的指针用于相同名称的函数而不会重载,auto_ptr不能在数组上使用,因为它调用了错误的删除类型。

看看这个:http://learningcppisfun.blogspot.com/2007/05/custom-deleters-with-smart-pointers.html

另请参阅有关数组智能指针的SO问题:auto_ptr for arrays

答案 5 :(得分:0)

让我觉得data_smart变量是三者中最愚蠢的。也就是说,当该范围结束时,auto_ptr析构函数将在其指针上调用delete而不是delete[],这将导致UB(这比data_dumb可能的内存泄漏更糟)。

所以,重点是不要将auto_ptr用于数组,使用vector。

在真正的问题上。首先,如果可能,使用引用参数而不是指针参数。如果无法做到这一点,请使用裸指针,auto_ptr::get()可以访问基础指针。

答案 6 :(得分:0)

忽略已经HAMMERED不要在数组上使用auto_ptr。

  

没有超载的最佳做法是什么?

看来你的方法不会取得所有权,所以剩下的问题是会改变吗?

  

将processData函数与uint32 *参数一起使用?

processData( uint32* )这是一个选择,但可能不是最好的选择 processData( uint32[123] )如果你没有编辑(123开始推动一些复制) processData( uint32 &[123] )通过ref并根据需要应用const。

  

我可以使用.get()将智能指针强制转换为uint32 *吗?

你可以使用get()获取智能指针的指针内容,它已经'打字'所以不需要强制转换它。

除了: 在这样一个原始级别的数据和操作应该在一个类中,你可能甚至不需要将成员变量应该传递给成员函数。

答案 7 :(得分:0)

在您的情况下,使用矢量是最安全的选择:

std::vector<uint32> data(123);

processData的签名理想情况应为:

void processData(const std::vector<uint32> & data);

但是,这个更频繁使用:

void processData(uint32 * bytes, int length);

在这两种情况下,您都可以使用矢量:

// 1
processData(data);

// 2
processData(data.data(), data.size());