C/C++ Arena

Step 6 of 7

Sink parameters and emplace_back

When a function or constructor is going to keep a string (store it in a member or a container), how should it take the parameter?

#include <iostream>
#include <string>
#include <utility>
#include <vector>

class Contact {
public:
    Contact(std::string name, std::string phone)
        : name_(std::move(name)), phone_(std::move(phone)) {}
    std::string line() const { return name_ + ": " + phone_; }

private:
    std::string name_;
    std::string phone_;
};

int main() {
    std::vector<Contact> book;
    std::string mine = "Ada";
    book.emplace_back(mine, "555-0101");        // mine is copied once; we still have it
    book.emplace_back("Grace", "555-0199");     // built in place from the literals
    book.push_back(Contact("Linus", "555-0142"));  // builds a temporary, then moves it in
    for (const auto& c : book) std::cout << c.line() << "\n";
    std::cout << "still have " << mine << "\n";
}
Ada: 555-0101
Grace: 555-0199
Linus: 555-0142
still have Ada

The cost for each kind of caller

emplace_back vs push_back

Use emplace_back when you have constructor arguments rather than an existing object.

Common mistake

Taking a parameter by value and then not moving it: name_(name) copies again. The std::move in the initializer is what makes the sink pattern pay off.

Your turn: give Player a sink constructor, and write void recruit(std::vector<Player>& team, std::string name) that adds a player using emplace_back and moves the name.

Previous: Moved-from objects Next: Challenge: a move-aware log