C++向量、返回与参数

发布于 2024-09-18 13:44:41 字数 560 浏览 4 评论 0原文

可能的重复:
如何在 C++ 中“返回对象”

我想知道是否有是以下三种方法之间的区别:

void FillVector_1(vector<int>& v) {
    v.push_back(1); // lots of push_backs!
}

vector<int> FillVector_2() {
    vector<int> v;
    v.push_back(1); // lots of push_backs!
    return v;
}

vector<int> FillVector_3() {
    int tab[SZ] = { 1, 2, 3, /*...*/ };
    return vector<int>(tab, tab + SZ);
}

Possible Duplicate:
how to “return an object” in C++

I am wondering if there is a difference between the three following approaches:

void FillVector_1(vector<int>& v) {
    v.push_back(1); // lots of push_backs!
}

vector<int> FillVector_2() {
    vector<int> v;
    v.push_back(1); // lots of push_backs!
    return v;
}

vector<int> FillVector_3() {
    int tab[SZ] = { 1, 2, 3, /*...*/ };
    return vector<int>(tab, tab + SZ);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

烛影斜 2024-09-25 13:44:41

最大的区别是第一种方式附加到现有内容,而其他两种方式填充空向量。 :)

我认为您正在寻找的关键字是 返回值优化,这应该是相当常见的(对于 G++,您必须专门将其关闭以防止应用它)。也就是说,如果用法如下:

vector<int> vec = fill_vector();

那么可能很容易就不会进行任何复制(并且该功能更易于使用)。

如果您正在使用现有向量

vector<int> vec;
while (something)
{
    vec = fill_vector();
    //do things
}

,那么使用 out 参数将避免在循环中创建向量并复制数据。

The biggest difference is that the first way appends to existing contents, whereas the other two fill an empty vector. :)

I think the keyword you are looking for is return value optimization, which should be rather common (with G++ you'll have to turn it off specifically to prevent it from being applied). That is, if the usage is like:

vector<int> vec = fill_vector();

then there might quite easily be no copies made (and the function is just easier to use).

If you are working with an existing vector

vector<int> vec;
while (something)
{
    vec = fill_vector();
    //do things
}

then using an out parameter would avoid creation of vectors in a loop and copying data around.

夜空下最亮的亮点 2024-09-25 13:44:41

惯用的 C++ 方法是使用输出迭代器对容器类型进行抽象:

template<typename OutputIterator>
void FillContainer(OutputIterator it) {
    *it++ = 1;
    ...
}

然后它可以与向量一起使用,如下所示:

std::vector<int> v;
FillContainer(std::back_inserter(v));

性能(以及其他优点,例如能够填充非空容器)与对于你的选择#1。另一个好处是,它可以用于以流模式输出,如果使用适当类型的迭代器(例如ostream_iterator),结果会立即处理并丢弃而不存储。

The idiomatic C++ approach would be to abstract over the container type by using an output iterator:

template<typename OutputIterator>
void FillContainer(OutputIterator it) {
    *it++ = 1;
    ...
}

Then it can be used with vector as:

std::vector<int> v;
FillContainer(std::back_inserter(v));

The performance (and other advantages, such as being able to fill a non-empty container) are the same as for your option #1. Another good thing is that this can be used to output in a streaming mode, where results are immediately processed and discarded without being stored, if the appropriate kind of iterator is used (e.g. ostream_iterator).

谁的新欢旧爱 2024-09-25 13:44:41

人们会认为参数是最好的,但实际上往往并非如此。这取决于编译器。某些编译器(我认为实际上是最新的编译器)将应用返回值优化 - Visual Studio 2005 及更高版本应该在您提供的两种情况下执行此操作(请参阅命名返回Visual C++ 2005 中的值优化)。

确定的最佳方法是检查所产生的拆卸结果。

One would assume parameter is best, but in practice it often is not. This depends on compiler. Some compilers (I think actually most recent compilers) will apply Return Value Optimization - Visual Studio 2005 and later should do it in both cases you have provided (see Named Return Value Optimization in Visual C++ 2005).

The best way to know for sure is to check the disassembly produced.

遮了一弯 2024-09-25 13:44:41

添加第四个变体:

void FillVector_4(vector<int>& v) {
   static const int tab[SZ] = {1,2,3, ... };
   v.assign(tab,tab+SZ);
}

如果您正在考虑版本 2 和版本 3 的性能,可能会让编译器为返回值创建一个 vector 副本。也就是说,如果编译器无法执行 NRVO(命名返回值优化)。此外,由于向量需要增长,连续的 push_back 没有 reserve 可能会导致几次重新分配。这是否重要取决于您要解决的问题。

您会很高兴知道 C++0x 将使返回本地创建的向量变得非常高效。我还建议阅读 David Abrahams 文章系列 关于有效值类型,包括传递/返回。

Adding a fourth variant into the mix:

void FillVector_4(vector<int>& v) {
   static const int tab[SZ] = {1,2,3, ... };
   v.assign(tab,tab+SZ);
}

If you're thinking about performance version 2 and version 3 may make the compiler create a vector<int> copy for the return value. That is, if the compiler isn't able to do NRVO (named return value optimization). Also, consecutive push_backs without a reserve probably leads to a couple of reallocations since the vector needs to grow. Whether this matters at all depends on your problem you're trying to solve.

You'll be pleased to know that C++0x will make returning a locally created vector very efficient. I also recommend reading David Abrahams article series about efficient value types including passing/returning.

我是男神闪亮亮 2024-09-25 13:44:41

第一个绝对不会复制向量。

复制向量的成本可能与向量中元素的数量成线性关系。

第一种方法不会在任何平台或编译器上引入线性行为的风险,也不会产生分析和重构的成本。

The first definitely does not copy the vector.

The cost of copying the vector could be linear in the number of elements in the vector.

The first introduces no risk of linear behavior on any platform or compiler, and no costs of profiling and refactoring.

茶色山野 2024-09-25 13:44:41

乍一看,前两个可能需要更多地调整向量大小,而第三个可能不需要在运行时调整向量大小。这可以通过在推迟之前自行调整大小来缓解。

At a glance, the first two probably have more resizing of the vector going on, whereas the 3rd one probably does not need to resize the vector as it runs. This can be mitigated by resizing it yourself before the pushbacks.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文