我完全理解这个问题已经被问了很多,但是我要求一个特定的变体,我的搜索foo已经放弃,因为我只找到附加一个的算法矢量到另一个,但没有一个从函数返回。
我有这个功能列出目录中的所有文件:
vector<string> scanDir( const string& dir )
可以在内部调用自己(对于子目录)。
我需要 short 方法将返回的值附加到调用者的向量中。我脑子里有这样的东西(当然它不存在:():
vector<string> fileList;
//...
fileList.append( scanDir(subdirname) );
我担心存储返回值并将其插入fileList会带来性能不佳。我的意思是:
vector<string> temp( scanDir(subdirname) );
copy( temp.begin(), temp.end(), back_inserter(fileList) );
谢谢!
PS:我并没有强迫自己使用vector,任何其他同样表现良好的容器并且可以阻止潜在的大型复制操作。我很好。
答案 0 :(得分:15)
为什么不将矢量作为参数传递?然后每个调用都可以附加到同一个向量,而无需复制。或者创建一个实现类,将元素累积到成员对象中。
答案 1 :(得分:9)
如果您有能力更改scanDir
,请将其设为接受输出迭代器的(模板)函数:
template <class OutIt>
void scanDir(const std::string& dirname, OutIt it) {
// ...
// Scan subdir
scanDir(subdir, it);
// ...
}
您可以获得额外的好处,以便能够填充所有类型的数据结构,如
std::vector<string> vector;
scanDir(dir1, std::back_inserter(vector));
std::set<string> fileset
scanDir(dir1, std::inserter(fileset, fileset.begin()));
等
编辑(见评论......)
对于使用此函数进行类成员初始化,您可以在构造函数中调用它,如在
中class MyClass {
private:
std::vector<string> m_fileList;
public:
MyClass(const std::string& dirname) {
scanDir(dirname, std::back_inserter(m_fileList);
}
}
或使用包装函数
std::vector<string> scanDir(const std::string& dirname) {
std::vector<string> result;
scanDir(dirname, std::back_inserter(result);
return result;
}
class MyClass {
// Same as above..
MyClass(const std::string& dirname) : m_fileList(scanDir(dirname)) { }
}
我更喜欢第一个版本的性能(和其他)原因......
答案 2 :(得分:8)
PS:我并没有强迫自己使用vector,任何其他同样表现良好的容器并且可以阻止潜在的大型复制操作。我很好。
好吧,如果您使用list
并致电a.splice(a.end(), b);
,您将完全避免复制操作。 list
通常是链接列表而不是数组,就像vector
一样,因此这会带来很多性能和使用含义。但是拼接在O(1)中运行,所以这是一个很好的好处。
答案 3 :(得分:3)
vector<string> fileList;
vector<string> temp( scanDir(subdirname) );
fileList.insert(fileList.end(), temp.begin(), temp.end());
我希望能帮助你。
答案 4 :(得分:2)
使用std :: list并使用std :: list :: splice附加。
该操作不涉及构造或销毁任何元素对象,除第三个版本外,它是在恒定时间内执行的。
答案 5 :(得分:1)
而不是
vector<string> temp( scanDir(subdirname) );
你可以做到
vector<string> const& temp = scanDir(subdirname);
继续复制:
fileList.insert(fileList.end(), temp.begin(), temp.end());
答案 6 :(得分:0)
递归函数必须多次复制所有内容,O(深度)才能准确(即:叶级别中的所有内容将一次又一次地复制,直到到达根目录。)
最好的方法是将其分为两个不同的功能:
vector<string> scanDir(string path)
{
vector<string> retval;
scanDir(path, &retval);
return retval;
}
static void scanDir(string path, vector<string>& output)
{
.. scan
.. append to output
}
答案 7 :(得分:0)
辅助函数怎么样?
template<class T>
std::vector<T>& VectorAppend(std::vector<T> &target, const std::vector<T> &source)
{
size_t insertPos = target.size();
target.resize(target.size() + source.size());
std::copy(source.begin(), source.end(), target.begin() + insertPos);
return target;
}
答案 8 :(得分:-1)
这可能不是最简单的解决方案,但是做一些与C#的StringBuilder等效的事情呢?
点击list<vector<string> >
,然后您可以将通过调用scanDir()
获得的所有向量附加到列表中。
如果你最后必须有一个向量,那么你可以在创建一个新向量后,将它分配得足够大,这样它就不需要调整大小,并组装你的成品。
或者,您可以创建一个新类(如果需要,它派生自vector&lt; T&gt;)并在内部使用列表&lt; vector&lt; T&gt; &GT;存储元素。然后你只需要让你的迭代器遍历第一个列表中的元素,然后当它到达结尾时去下一个列表中的元素,只有当你到达最后一个列表的末尾时才返回container :: end。
答案 9 :(得分:-1)
我知道这并没有直接回答你的问题,但就你的基本目标而言,你可能只想简单地在boost :: filesystem方面重新实现你的功能。目录迭代器已经递归,因此您不需要进行自己的递归调用。您可以简单地在迭代器上的循环中填充列表。有一个ls的示例实现: http://www.boost.org/doc/libs/1_43_0/libs/filesystem/example/simple_ls.cpp
您还可以获得(理论上)平台独立性的更多好处,相对广泛的采用(通过更多采用可以更快地发现错误)等等