Assuming the capacity of existing member has been pre-allocated and sufficient for the passed object.
// For lvalue argument:
void setter(const std::string & m) { _member = m; }
// For rvalue argument:
void setter(std::string&& m) { _member = std::move(m); }
// For lvalue/rvalue argument:
void setter(const std::string & m) { _member = m; }
There are several common approaches to writing setters in modern C++. Today, we will benchmark three major patterns and analyze their performance.
GCC: https://quick-bench.com/q/PbEMn4tk0uYIZWC9_ZJ3Oi9R0V8

Clang: https://quick-bench.com/q/6cCqUiQ56fL0eyT2Vu49doSc1bA

class Person {
public:
Person() : name("Constantdw wwdw dqwdfqwyypfn;qwlnm5465"){}
void setName1(std::string n) {
name = std::move(n);
}
void setName2(const std::string& n) {
name = n;
}
private:
std::string name;
};
static void setName1_lvalue(benchmark::State& state) {
// Code inside this loop is measured repeatedly
Person person;
std::string name = "Constantdw wwdw dqwdfqwyypfn";
for (auto _ : state) {
person.setName1(name);
}
}
BENCHMARK(setName1_lvalue);
static void setName2_lvalue(benchmark::State& state) {
// Code inside this loop is measured repeatedly
Person person;
std::string name = "Constantdw wwdw dqwdfqwyypfn";
for (auto _ : state) {
person.setName2(name);
}
}
BENCHMARK(setName2_lvalue);
GCC: https://quick-bench.com/q/mUFg5UXJj28ZTqtE2v7eGr30T70

Clang: https://quick-bench.com/q/a1pANo1yjRH3K_mjUq7AfttJx7E

class Person {
public:
Person() : name("Constantdw wwdw dqwdfqwyypfn;qwlnm5465"){}
void setName1(std::string n) {
name = std::move(n);
}
void setName2(const std::string& n) {
name = n;
}
void setName3(std::string&& n) {
name = std::move(n);
}
private:
std::string name;
};
static void setName1_rvalue(benchmark::State& state) {
// Code inside this loop is measured repeatedly
Person person;
std::string name = "Constantdw wwdw dqwdfqwyypfn";
for (auto _ : state) {
person.setName1(std::move(name));
}
}
BENCHMARK(setName1_rvalue);
static void setName2_rvalue(benchmark::State& state) {
// Code inside this loop is measured repeatedly
Person person;
std::string name = "Constantdw wwdw dqwdfqwyypfn";
for (auto _ : state) {
person.setName2(std::move(name));
}
}
BENCHMARK(setName2_rvalue);
static void setName3_rvalue(benchmark::State& state) {
// Code inside this loop is measured repeatedly
Person person;
std::string name = "Constantdw wwdw dqwdfqwyypfn";
for (auto _ : state) {
person.setName3(std::move(name));
}
}
BENCHMARK(setName3_rvalue);
For the remaining cases, I summarize them in the table for easier comparison.
| lvalue argument | rvalue argument | |
|---|---|---|
| Take by value and assign | Copy construct, then move assign | Move construct, then move assign |
| Take by const lvalue ref and assign | Copy assign | Copy assign |
| Take by rvalue ref and assign | N/A | Move assign |
$\dagger$ Assuming the capacity of existing member is greater than or equal to the passed object. Ie., no allocation occurs in copy/move assignment