从C ++函数返回指针的推荐方法?

时间:2011-06-21 09:52:10

标签: c++ pointers

我有一个传递给一系列函数的指针,其中一个函数返回一个地址并将该地址分配给指针。在Stackoverflow上寻求帮助后,collect_file_path方法的参数类型为QStringList**。虽然我明白发生了什么,但我没有在我拥有的任何教科书中看到这种符号,而且看起来很难看。

我想就其他程序员如何实现我在下面的代码中所做的工作提供一些建议/反馈。您会使用QStringList**还是其他方法?

我希望我所要求的是有道理的。我目前的代码是:

void ThreadWorker::run()
{
  QStringList* file_list;
  collect_file_paths(&file_list);
}

void ThreadWorker::collect_file_paths(QStringList** file_list)
{
  DirectorySearch ds;
  *file_list = ds.get_file_names(_strPath);
}

QStringList* DirectorySearch::get_file_names(QString path)
{
  QStringList *file_names = new QStringList;
  traverse(path, file_names);
  return file_names;
}

由于

7 个答案:

答案 0 :(得分:3)

返回裸指针的问题是,最终泄漏对象的内存很容易。例如,如果函数中的任何内容抛出,可能会发生这种情况;但是在调用者收到指针之前也可能发生这种情况(例如,如果它被用作函数的参数,并且另一个参数的评估抛出)。

由于这些原因,最好将指针包装在智能指针中,如std::auto_ptr(即将发布的C ++标准中的unique_ptr)或boost::shared_ptr(也可用std::shared_ptr,很快就在你附近的标准图书馆里)。当这时候,这些包装器将安全地删除包装的指针。

但是,在这种特定情况下,您可以通过传递QStringList**作为参考来管理而不使用QStringList*

答案 1 :(得分:2)

您也可以通过指针引用传递,这是更多C ++风格:

void ThreadWorker::collect_file_paths(QStringList*& file_list) <-- see *&
{
}

您现在不必传递file_list的地址:

collect_file_paths(file_list);  // simply pass it

但不是这样,我仍然会建议采用以下方法(更简单):

void ThreadWorker::run()
{
  QStringList* file_list = collect_file_paths();
}

QStringList* ThreadWorker::collect_file_paths()
{
  DirectorySearch ds;  //<---- ds uninitialized
  return ds.get_file_names(_strPath);  // for static function use ClassName::method() style
}

答案 2 :(得分:2)

只需按价值返回。编译器可以是RVO,NRVO,你可以互换。

答案 3 :(得分:2)

您可以按值返回,因为不必要的副本将被优化掉。 这是一个明确的,异常安全的和我推荐的方式。

void ThreadWorker::run()
{
  QStringList file_list = collect_file_paths();
}

QStringList ThreadWorker::collect_file_paths()
{
  DirectorySearch ds;
  return ds.get_file_names(strPath_);  // you should not use leading underscore in c++
}

QStringList DirectorySearch::get_file_names(QString path)
{
  QStringList file_names;
  traverse(path, &file_names);
  return file_names;
}

http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

顺便说一下。我认为Qt Containers具有写入优化的副本,因此即使没有编译器优化,副本也会很便宜。

如果你不信任(非常常见的)编译器优化,比如RVO(由heishe评论),你不使用像QStringList这样的写时复制对象,你应该在run()方法中创建实例并传递对其他函数的引用。这不像我推荐的技术那么清晰,但仍然是例外安全(至少是基本保证)。

void ThreadWorker::run()
{
  QStringList file_list;
  collect_file_paths(file_list);
}

void ThreadWorker::collect_file_paths(QStringList& file_list)
{
  DirectorySearch ds;
  ds.get_file_names(strPath_, file_list);  
}

void DirectorySearch::get_file_names(QString path, QStringList& file_list)
{
  traverse(path, &file_list);
}

第三种解决方案是返回类似std::unique_ptr<QStringList>的智能指针。但是在这个例子中我看不出有任何额外动态分配的原因。

答案 4 :(得分:0)

它可能看起来很丑,但在某些API中传递双指针并不常见。

在你的情况下似乎没必要。为什么collect_file_paths不仅仅返回一个指针?

答案 5 :(得分:0)

如果已使用new-operator分配内存,则只需返回指针即可。另外,请记住对已分配的内存使用delete。这个的好地方通常是在析构函数方法中(不是在这种情况下,因为你只在run-method中使用内存)。

void ThreadWorker::run()
{
  QStringList* file_list;
  file_list = ds.get_file_names(_strPath);

  //here we do something with file_list
  //...

  //Free the memory. You have to do this if the object pointed by file_list is not
  //used anywhere else.
  delete file_list;
}

QStringList* DirectorySearch::get_file_names(QString path)
{
  QStringList *file_names = new QStringList;
  traverse(path, file_names);
  return file_names;
}

答案 6 :(得分:0)

假设用户可以访问标题而不是实现,他/她不知道如何处理指针。如果你的函数是一个源(也就是用new分配指针),你应该返回一个auto_ptr。 auto_ptr是:标准,永不抛出,专门设计来完成这项工作。

您可以查看此http://www.gotw.ca/publications/using_auto_ptr_effectively.htm