Tweaks
- Item 41: Pass by Value for Copyable, Cheap-to-Move Parameters
- Item 42: Prefer Emplacement over Insertion
- Multiple-Choice Questions
- Design Questions
- Answers & Explanations
- Multiple-Choice Answers
- Design Answers
- Test Cases
Item 41: Pass by Value for Copyable, Cheap-to-Move Parameters
Core Idea:
- Use pass-by-value when parameters are:
- Copyable (supports copy and move operations).
- Cheap to move (e.g., built-in types, small objects).
- Always copied (copied unconditionally inside the function).
- Avoids redundant copies when arguments are rvalues.
Example:
class Widget { std::string name;
public: // Pass by value + move avoids one copy for rvalues. Widget(std::string n) : name(std::move(n)) {}
}; // Usage:
Widget w1("Hello"); // Constructs from rvalue (efficient).
std::string s = "World";
Widget w2(s); // Copies s into n, then moves to name.
Test Case:
#include <iostream>
#include <string> class Widget {
public: std::string name; Widget(std::string n) : name(std::move(n)) { std::cout << "Widget constructed\n"; }
}; int main() { std::string s = "Test"; Widget w1(s); // 1 copy (s → n), 1 move (n → name). Widget w2("Hello"); // 0 copies (direct move from rvalue).
}
Item 42: Prefer Emplacement over Insertion
Core Idea:
- Use
emplace_back
/emplace
instead ofpush_back
/insert
to:- Avoid temporary object construction.
- Enable direct in-place construction.
- Exceptions:
- When explicit conversions are needed (e.g.,
vector<Base>
withDerived
). - When container might reallocate (risk of resource leaks).
- When explicit conversions are needed (e.g.,
Example:
std::vector<std::string> vec;
vec.push_back("Hello"); // Creates temporary std::string.
vec.emplace_back("World"); // Constructs directly in place (no temporary).
Test Case:
#include <vector>
#include <string> int main() { std::vector<std::string> vec; vec.reserve(2); vec.push_back("Hello"); // Temporary string created → moved. vec.emplace_back("World"); // Direct construction in memory.
}
Multiple-Choice Questions
-
When is pass-by-value NOT recommended?
A) Forstd::unique_ptr
parameters.
B) For small, copyable types always copied.
C) For parameters used conditionally.
D) For types with expensive move operations. -
Why prefer
emplace_back
overpush_back
?
A) To avoid type conversions.
B) To reduce temporary object constructions.
C) To enforce explicit constructors.
D) To prevent container reallocations. -
Which scenario risks resource leaks with
emplace
?
A) Usingemplace_back
withstd::make_shared
.
B) Usingemplace
in astd::vector
of integers.
C) Usingemplace
withstd::string
in a non-reallocating vector.
D) Usingemplace
with raw pointers. -
What is the type of
n
inWidget(std::string n)
?
A)std::string&
B)const std::string&
C)std::string
D)std::string&&
-
When does
push_back
outperformemplace_back
?
A) When constructing from an lvalue.
B) When the container has sufficient capacity.
C) When using explicit constructors.
D) Never.
Design Questions
- Design a function
addToVector
that takes astd::vector<std::string>
and a string parameter, using optimal parameter passing. - Modify a
std::vector<Base>
to safely acceptDerived
objects via insertion/emplacement. - Implement a
Logger
class where pass-by-value avoids redundant copies. - Write a
template
function to forward arguments toemplace_back
. - Identify and fix a resource leak in
emplace
usage withstd::shared_ptr
.
Answers & Explanations
Multiple-Choice Answers
- C (Parameters used conditionally may incur unnecessary copies.)
- B (
emplace
constructs in-place, avoiding temporaries.) - D (Raw pointers in
emplace
can leak if reallocation occurs.) - C (Pass-by-value creates a copy/moveable parameter.)
- C (
push_back
ensures explicit conversions;emplace
might bypass them.)
Design Answers
-
Optimal
addToVector
:void addToVector(std::vector<std::string>& vec, std::string s) { vec.push_back(std::move(s)); // Move if possible. }
-
Safe
Derived
Insertion:std::vector<std::unique_ptr<Base>> vec; vec.push_back(std::make_unique<Derived>()); // Safe insertion. // vec.emplace_back(new Derived); // Unsafe (potential leak).
-
Logger Class:
class Logger { std::string data; public: Logger(std::string d) : data(std::move(d)) {} };
-
Emplace Forwarding:
template<typename T, typename... Args> void emplaceAdd(std::vector<T>& vec, Args&&... args) { vec.emplace_back(std::forward<Args>(args)...); }
-
Fix Shared_ptr Leak:
std::vector<std::shared_ptr<Widget>> vec; vec.push_back(std::make_shared<Widget>()); // Safe. // vec.emplace_back(new Widget); // Risky (use make_shared).
Test Cases
For Item 41:
int main() { std::vector<std::string> vec; std::string s = "Hello"; addToVector(vec, s); // Copy + move. addToVector(vec, "World"); // Direct move.
}
For Item 42:
int main() { std::vector<std::unique_ptr<Base>> vec; vec.reserve(10); vec.push_back(std::make_unique<Derived>()); // Safe. // vec.emplace_back(new Derived); // Risk of leak.
}
This structured approach ensures mastery of parameter passing and emplacement optimizations in Modern C++!