I'm testing what constructs generate object creation, copy, move, or just pass-on. This post is a log of test code, trials, errors.
Test classes
#include <iostream>
#include <array>
#include <string>
template <class T> struct result {
result() { // default constructor
std::cout << "result<T> constructor\n";
}
T check;
constexpr explicit operator bool() const noexcept { return static_cast<bool>(check); }
};
struct bool_class{
bool_class() { std::cout << "bool_class constructor\n"; } // default constructor
bool_class(const bool_class& other) { std::cout << "bool_class copy constructor\n"; } // copy constructor
bool_class(bool_class&& other) noexcept { std::cout << "bool_class move constructor\n"; } // move constructor
bool_class& operator =(const bool_class& other) { // copy assignment operator
std::cout << "bool_class copy assignment operator\n";
return *this;
}
bool_class& operator = (bool_class&& other) noexcept { // move assignment operator
std::cout << "bool_class move assignment operator\n";
return *this;
}
constexpr explicit operator bool() const noexcept{ return true; } // status return, obviously test code
};
Test functions (object factory and similar)
using bool_result = result<bool_class>;
bool_result get_bool_result() { // factory method
bool_result br; // calls default constructor and result<T> constructor
return br;
}
bool_result get_bool_result(bool_class& bc) {
bool_result br; // calls default constructor and result<T> constructor
br.check = bc; // calls copy assignment operator
return br;
}
bool_result get_bool_result(bool_class&& bc) {
bool_result br; // calls default constructor and result<T> constructor
br.check = std::move(bc); // calls move assignment operator
return br;
}
bool_result& get_bool_result(bool_result& br) { // calls nothing, zero cost
return br;
}
bool_result&& get_bool_result(bool_result&& br) { // calls nothing, zero cost
return br;
}
Test code
int main() {
if ( auto&& [check] = get_bool_result()) { // calls default constructor inside the function
std::cout << "success\n";
std::cout << (bool)check << "\n";
bool_class a = check; // calls copy constructor
// bool_class&& b = check; // invalid
bool_class c = std::move(check); // calls move constructor
bool_class&& d = std::move(check); // calls nothing
bool_class e(check); // calls copy constructor
// bool_class&& f(check); // invalid
bool_class g(std::move(check)); // calls move constructor
bool_class&& h(std::move(check)); // calls nothing
bool_class i = a; // calls copy constructor
// bool_class&& j = a; // invalid
bool_class k = d; // calls copy constructor
// bool_class&& l = d; // invalid
bool_class m = std::move(a); // calls move constructor
bool_class&& n = std::move(a); // calls nothing
bool_class o = std::move(d); // calls move constructor
bool_class&& p = std::move(d); // calls nothing
a = check; // calls copy assignment operator
d = check; // calls copy assignment operator
e = check; // calls copy assignment operator
g = std::move(check); // calls move assignment operator
h = std::move(check); // calls move assignment operator
std::array<bool_class,1> ar_a; // calls copy constructor
ar_a[0] = a; // calls copy assignment operator
ar_a[0] = d; // calls copy assignment operator
ar_a[0] = std::move(a); // calls move assignment operator
ar_a[0] = std::move(d); // calls move assignment operator
std::array<bool_class,1> ar_b = {a}; // calls copy constructor
std::array<bool_class,1> ar_c = {check}; // calls copy constructor
std::array<bool_class,1> ar_d = {std::move(a)}; // calls move constructor
std::array<bool_class,1> ar_e = {std::move(check)}; // calls move constructor
if ( auto&& [check] = get_bool_result(a)) {} // calls copy assignment operator
if ( auto&& [check] = get_bool_result(std::move(a))) {} // calls move assignment operator
bool_result br; // calls default constructor and result<T> constructor
if ( auto&& [check] = get_bool_result(br)) {} // calls nothing, zero cost
if ( auto&& [check] = get_bool_result(std::move(br))) {} // calls nothing, zero cost
}
}
I documented the pieces of code that either called a constructor or an assignment operator. Both use some resources (just like creating or assigning to a variable cost something).
Some constructs have a comment // calls nothing. These don't use resources (no memory, cpu time, binary code size).
Requires GCC 15