diff --git a/Makefile b/Makefile
index 156120a..6e401d4 100644
--- a/Makefile
+++ b/Makefile
@@ -22,8 +22,7 @@ tracy_build:
meson compile -j 10 -C builddir
test: build
- ./builddir/emplace_test.exe
- ./builddir/rvo_test.exe
+ ./builddir/emplace_test.exe "[proof]"
clean:
meson compile --clean -C builddir
diff --git a/emplace_move/test.cpp b/emplace_move/test.cpp
index dee87ae..9a49736 100644
--- a/emplace_move/test.cpp
+++ b/emplace_move/test.cpp
@@ -7,34 +7,88 @@
using namespace fmt;
+struct Counts {
+ int default_constructor = 0;
+ int value_constructor = 0;
+ int copy_constructor = 0;
+ int move_constructor = 0;
+ int move_assign = 0;
+ int copy_assign = 0;
+ int destructor = 0;
+
+ void reset() {
+ default_constructor = 0;
+ value_constructor = 0;
+ copy_constructor = 0;
+ move_constructor = 0;
+ move_assign = 0;
+ copy_assign = 0;
+ destructor = 0;
+ }
+
+ int totals() {
+ return default_constructor +
+ value_constructor +
+ copy_constructor +
+ move_constructor +
+ move_assign +
+ copy_assign +
+ destructor;
+ }
+
+ void dump() {
+ fmt::println("default_constructor {} value_constructor {} copy_constructor {} move_constructor {} move_assign {} copy_assign",
+ default_constructor,
+ value_constructor,
+ copy_constructor,
+ move_constructor,
+ move_assign,
+ copy_assign,
+ destructor);
+ }
+};
+
+Counts COUNTS;
+
// Some heavy object
struct A {
- A() = default;
+ int val = 0;
+
+ A() {
+ COUNTS.default_constructor++;
+ std::cout << "default called constructor with: " << val << std::endl;
+ }
A(int val) : val(val) {
+ COUNTS.value_constructor++;
std::cout << "called constructor with: " << val << std::endl;
}
A(A const& other) {
+ COUNTS.copy_constructor++;
std::cout << "calling copy(A const& other): " << val << std::endl;;
}
A(A&& other) {
+ COUNTS.move_constructor++;
std::cout << "calling move(A&& other): " << val << std::endl;;
}
A& operator=(A&& other) {
+ COUNTS.move_assign++;
std::cout << "calling move(A&& other)=: " << val << std::endl;;
return *this;
}
A& operator=(A const& other) {
+ COUNTS.copy_assign++;
std::cout << "calling copy(A const& other)=: " << val << std::endl;;
return *this;
}
- ~A() = default;
-
- int val{};
+ ~A() {
+ COUNTS.destructor++;
+ std::cout << "destructor called" << std::endl;
+ }
};
@@ -92,9 +146,68 @@ TEST_CASE("pushback move tests", "[push_back]") {
// to put the value in a slot so the compiler had to call the move constructor
std::cout << "== 4. Push Back: Calling move constructor\n";
test.push_back(A{});
+
}
TEST_CASE("proof you don't need emplace or std::move", "[proof]") {
+ A a{20};
+ A b{30};
+ COUNTS.reset();
+
+ std::vector emtest;
+ emtest.reserve(10);
+
+ std::vector pbtest;
+ pbtest.reserve(10);
+ REQUIRE(COUNTS.totals() == 0);
+
+ emtest.emplace_back(a);
+ REQUIRE(COUNTS.totals() == 1);
+ COUNTS.dump();
+ COUNTS.reset();
+
+ pbtest.push_back(b);
+ REQUIRE(COUNTS.totals() == 1);
+ COUNTS.dump();
+ COUNTS.reset();
+
+ // confirm these do the same number of calls
+ emtest.emplace_back(A{});
+ REQUIRE(COUNTS.totals() == 3);
+ COUNTS.dump();
+ COUNTS.reset();
+
+ pbtest.push_back(A{});
+ REQUIRE(COUNTS.totals() == 3);
+ COUNTS.dump();
+ COUNTS.reset();
+
+ {
+ REQUIRE(COUNTS.totals() == 0);
+
+ A c{};
+ emtest.emplace_back(std::move(c));
+ REQUIRE(COUNTS.totals() == 2);
+ COUNTS.dump();
+ COUNTS.reset();
+
+ A d{};
+ pbtest.push_back(std::move(d));
+ REQUIRE(COUNTS.totals() == 2);
+ COUNTS.dump();
+ COUNTS.reset();
+ }
+
+ COUNTS.reset();
+
+ emtest.emplace_back(200);
+ REQUIRE(COUNTS.totals() == 1);
+ COUNTS.dump();
+ COUNTS.reset();
+ pbtest.push_back(200);
+ REQUIRE(COUNTS.totals() == 3);
+ COUNTS.dump();
+ COUNTS.reset();
}