将 RVO 对象传递给 std::vector::emplace_back

Pass RVO object to std::vector::emplace_back

考虑以下数组:

std::vector<Foo> arr;
arr.emplace_back(calculate_foo());

emplace_back 受益于消除临时对象,因为它的参数在新构造的元素上就地传递(所以这里 emplace_back 会触发移动或复制构造函数)Foo(foo)

上面的代码当然会在 calculate_foo 中创建一个临时对象,然后根据 Foo 的构造函数将其复制或移动到新数组。

有没有机会让它更快并消除临时对象?

您无法避免使用 emplace_backFoo 的构造函数创建临时参数。如果您使用 Foo 类型的参数,那么它就是将传递给放置对象的构造函数的临时对象。在这种情况下,push_back 将同样有效。

要真正利用安置,您的类型需要有一个构造函数,该构造函数采用一些轻量级参数,可用于构造更昂贵的对象。这样,只有临时对象才是轻量级对象。为了直接从 return 值放置,该构造函数只能采用单个参数。

示例:

struct ExpensiveMove {
    explicit ExpensiveMove(double d) {
         std::cout << "construct\n";
         std::fill(arr.begin(), arr.end(), d);
    }

    ExpensiveMove(const ExpensiveMove&) { std::cout << "expensive copy\n"; }
    ExpensiveMove(ExpensiveMove&&) { std::cout << "expensive move\n"; }
    ExpensiveMove& operator=(const ExpensiveMove&) { std::cout << "expensive copy ass\n"; return *this; }
    ExpensiveMove& operator=(ExpensiveMove&&) { std::cout << "expensive move ass\n"; return *this; }
    std::array<double, 1024> arr;
};

double calculate()
{
    return 4.2;
}

int main() {
    std::vector<ExpensiveMove> arr;
    arr.emplace_back(calculate());
}

本例中没有 ExpensiveMove 类型的临时对象。有一个临时的替身,没关系。