【问题标题】:Optimizing vector assignment c++优化向量赋值 c++
【发布时间】:2016-01-30 22:16:03
【问题描述】:

我有一个返回向量的函数。让我们将其命名为v。我在函数中使用v.begin()v.end()。我怎么能使用.begin().end() 而不创建一个新的向量v2 来存储以前的向量v 以便我可以访问方法?

这就是我的意思:

std::vector<int> merge(...) {
    ...
    return v;
}
void mergeSort(...) {
    ...
    std::vector<int> v2;
    v2 = merge(...);
    I_need_this = v2.begin();
    And_I_really_need_this_too = v2.end();
    ...
}

【问题讨论】:

    标签: c++ algorithm vector


    【解决方案1】:

    优化赋值的最好方法是根本不赋值,而是使用初始化

    std::vector<int> v2 = merge(...);
    

    几乎可以肯定,编译器会直接将v创建成v2,无需任何复制。

    【讨论】:

    • 使用move构造函数
    • 我在创建帖子之前尝试过。效果不好。
    • 试试 std::vector v2 = std::move(merge(...));
    • @Vincent merge(....) 已经是一个右值,所以这实际上是一种悲观
    • @ValeryBaturin 这是正确的答案,如果您仍然遇到问题,那么还有另一个您没有显示代码的错误。如果您发布一个显示问题的实际程序,而不是一堆点,那就更好了。 See here for guidelines.
    【解决方案2】:

    当您需要返回集合时,为了防止它们被复制,一种常见的模式是通过非常量引用传递集合并对原始集合进行更改。这意味着调用者负责实例化集合,而不是被调用者,因此不会发生任何副本。这是一个例子:

    void merge(std::vector<int> & result, ...) {
    
        // Do changes to result
        ...
    }
    void mergeSort(...) {
        ...
        std::vector<int> v;
        merge(v, ...);
    
        // This is OK now
        I_need_this = v.begin();
        And_I_really_need_this_too = v.end();
        ...
    }
    

    【讨论】:

    • 我不喜欢这个,因为你总是需要在使用函数之前创建向量。但无论如何,这是一个解决方案。谢谢!
    • 我很好,但我希望你明白这是返回集合时的事实上的标准。在某些情况下,接受的答案仍会创建一个副本,通常最好设计您的代码以涵盖各种场景。例如,请记住,在 C 中您甚至不能返回数组。此外,如果您仍然创建它,那么之前创建它有什么问题?编码愉快!
    • @AndréFratelli:在设置它的值之前创建它的两个最大问题 a) 你不能声明它 const ; b) 风格很差。如果调用者重用变量而忘记清除它,这也是一个潜在的问题。
    • @MartinBonner 我同意你不能将它声明为 const,但是你可以制作一个 const 副本。考虑到风格很差,那就是你大错特错的地方。就像我说的,在返回集合时,这是编程中事实上的 标准,您会在文献中找到很多。你不喜欢它的事实是无关紧要的,因为它确实是这个问题通常是如何解决的,即使移动构造函数可用。见this讨论
    • 这不是事实上的标准;这是选择之一——通常是一个糟糕的选择。该讨论是关于它确实具有 一些 优势(通过返回类型重载)的情况之一 - 但正确的解决方案将有不同的函数名称(尽管在模板化代码中可能会出现问题)。
    【解决方案3】:

    您可以将您的向量临时绑定到参考:

    extern std::vector<int> f();
    
    auto&& x = f();
    std::sort(x.begin(), x.end());  // example
    

    【讨论】:

    • ‘function’既有‘extern’又有初始化器extern std::vector function(...);
    【解决方案4】:

    您有多种选择:

    1. 别担心。性能通常不是那么重要。

    2. 开启优化(您会惊讶于该步骤解决了多少关于 SO 的“优化”问题)。

    3. 升级到 C++11 编译器。编译器应该对向量使用移动赋值运算符,这是非常有效的(任何体面的库都会将内部分配的数组从临时转移到目标,无需内存分配和元素复制)。

    4. 如果您不能使用 C++11 编译器,或者您已经测量过,这仍然是性能瓶颈,请按照 Bo Person 在his answer 中的建议切换到初始化

    5. 如果您已经测量,而这仍然是性能瓶颈,并且您无法让编译器实现 RVO,那么您别无选择,只能传递向量根据 André Fratelli 在his answer

    6. 中的建议

    如果我们不再讨论优化,而是讨论编写好的、清晰的代码,那么我会按优先顺序推荐:

    • 从函数结果初始化
    • 函数结果赋值
    • 传入要填充的向量。

    【讨论】:

    • 我可以使用 c++11,但没有让程序变慢的选项。我有时间限制的比赛等等。谢谢您的回答。 RVO 很酷,我听说过。
    猜你喜欢
    • 2020-11-02
    • 2016-12-14
    • 2018-12-08
    • 2011-07-06
    • 1970-01-01
    • 1970-01-01
    • 2020-07-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多