C++将一个向量附加到另一个向量
我完全理解这个问题已经被问了很多次,但我要求的是一种特定的变体,而我的 search-foo 已经放弃了,因为我只找到了将一个现有向量附加到另一个向量的算法,但没有从函数返回。
我有一个列出目录中所有文件的函数:
vector<string> scanDir( const string& dir )
它可以在内部调用自身(对于子目录)。
我需要一种将返回值附加到调用者向量的简短方法。我脑子里有这样的东西(但当然它不存在:( ):
vector<string> fileList;
//...
fileList.append( scanDir(subdirname) );
我担心存储返回值并将其插入 fileList 会带来性能问题。我的意思是:
vector<string> temp( scanDir(subdirname) );
copy( temp.begin(), temp.end(), back_inserter(fileList) );
谢谢!
PS:我'我不强迫自己使用向量,任何其他性能同样出色并且可以防止潜在的大型复制操作的容器对我来说都很好。
I fully understand this question has been asked a lot, but I'm asking for a specific variation and my search-foo has given up, as I've only found algorithms that append one existing vector to another, but not one returned to from a function.
I have this function that lists all files in a directory:
vector<string> scanDir( const string& dir )
which may call itself internally (for subdirectories).
I need a short way of appending the returned value to the caller's vector. I have in my mind something like this (but of course it doesn't exist :( ):
vector<string> fileList;
//...
fileList.append( scanDir(subdirname) );
I fear that storing the return value and inserting it in fileList would bring performance badness. What I mean is this:
vector<string> temp( scanDir(subdirname) );
copy( temp.begin(), temp.end(), back_inserter(fileList) );
Thanks!
PS: I'm not forcing myself to using vector, any other container that performs equally well and can prevent the potential large copy operation is fine by me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
为什么不直接将向量作为参数传递呢?然后每次调用都可以附加到同一个向量,而无需复制。或者创建一个实现类,将元素累积到成员对象中。
Why not just pass the vector as an argument? Then every invocation can append to the same vector, without copying. Or create an implementation class which accumulates the elements into a member object.
如果您可以更改
scanDir
,请将其设为接受输出迭代器的(模板)函数:您将获得额外的好处,能够填充各种数据结构,例如
等。
编辑(请参阅注释...)
要使用此函数进行类成员初始化,您可以在构造函数中调用它,
或者使用包装函数,
出于性能考虑,我更喜欢第一个版本(以及其他版本) ) 原因...
If you're in the position to change
scanDir
, make it a (template) function accepting an output iterator:You'll have the additional benefit to be able to fill all sort of data structures like
etc.
EDIT (see comment ...)
For using this function for class member initialization, you could either call it in the constructor as in
or using a wrapper function
I would prefer the first version for performance (and other) reasons ...
好吧,如果您使用
list
并调用a.splice(a.end(), b);
您将完全避免复制操作。list
通常是一个链表,而不是像vector
那样的数组,因此这对性能和使用有很大影响。但是 splice 的运行时间复杂度为 O(1),所以这是一个很好的好处。Well, if you use a
list
and calla.splice(a.end(), b);
you'll avoid the copy operation completely. Alist
is generally going to be a linked list rather than an array as is the case with avector
, so this has a lot of performance and usage implications. But splice runs in O(1), so that's a nice benefit.我希望这对你有帮助。
I hope that helped you.
使用 std::list 并使用 std::list::splice 追加。
来自拼接文档:
Use std::list and append by using std::list::splice.
From the docs for splice:
相反,
您可以执行
并继续复制:
Instead of
you can do
and proceed with the copy:
递归函数必须多次复制所有内容,准确地说是 O(深度)(即:叶级别中的所有内容都将被一次又一次复制,直到到达根)。
最好的方法是将其分成两个不同的函数:
The recursive function will have to copy everything multiple times, O(depth) to be precise (i.e: everything in the leaf level will be copied again and again until it reaches the root).
The best method would be splitting this into two different functions:
辅助功能怎么样?
How about a helper function?
这可能不是最简单的解决方案,但是做一些相当于 C# 的 StringBuilder 的事情怎么样?
创建一个
列表<向量<字符串> >
然后您可以将从调用scanDir()
中获得的所有向量附加到列表中。如果您绝对必须在最后有一个向量,那么一旦创建一个新向量,您就可以将其分配得足够大,以便不需要调整大小,然后组装您的成品。
或者,您可以创建一个新类(如果需要,从向量派生)并在内部使用列表<向量。 >来存储元素。然后,您只需让迭代器迭代第一个列表中的元素,然后当它到达末尾时,转到下一个列表中的元素,仅在到达最后一个列表的末尾时返回 container::end 。
This might not be the simplest possible solution, but what about doing something equivalent to C#'s StringBuilder?
Make a
list<vector<string> >
then you can append all of the vectors that you get from your calls toscanDir()
to the list.If you absolutely have to have a single vector at the end, you can then, once make a new vector, allocate it large enough so that it won't need to resize, and assemble your finished product.
Alternatively, you could make a new class (if needed that derives from vector<T>) and internally uses the list<vector<T> > to store the elements. Then you would just make your iterators iterate through the elements in the first list, then when it reaches the end go for the elements in the next list, only returning container::end when you reached the end of the last list.
我知道这并不能直接回答您的问题,但就您的根本目标而言,您可能只想简单地根据 boost::filesystem 重新实现您的函数。目录迭代器已经是递归的,因此您不需要自己进行递归调用。您可以简单地在迭代器上的循环中填充列表。有一个 ls 的示例实现:
http://www.boost.org/doc/ libs/1_43_0/libs/filesystem/example/simple_ls.cpp
您还可以获得(理论上的)平台独立性、相对广泛的采用(采用更多的情况下可以更快地发现错误)等额外好处
I know this doesn't answer your question directly, but with regard to your underlying goal, you might want to simply reimplement your function in terms of boost::filesystem. The directory iterator is already recursive so you don't need to make recursive calls of your own. You could simply populate a list in a loop over the iterator. There is an example implementation of ls:
http://www.boost.org/doc/libs/1_43_0/libs/filesystem/example/simple_ls.cpp
You also get the added benefit of (theoretical) platform independence, relatively wide adoption (bugs get ferreted out more quickly with more adoption), etc