From e308552eccbab74069c30bc2234cd26e5e5e1f9f Mon Sep 17 00:00:00 2001 From: Julian Brost Date: Thu, 6 Mar 2025 11:46:48 +0100 Subject: [PATCH] Add test that std::vector uses move overloads --- test/CMakeLists.txt | 1 + test/base-string.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a255178da..6ceb48683 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -165,6 +165,7 @@ add_boost_test(base base_string/replace base_string/index base_string/find + base_string/vector_move base_timer/construct base_timer/interval base_timer/invoke diff --git a/test/base-string.cpp b/test/base-string.cpp index 835b1a643..5b28c5481 100644 --- a/test/base-string.cpp +++ b/test/base-string.cpp @@ -1,6 +1,7 @@ /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #include "base/string.hpp" +#include #include using namespace icinga; @@ -101,4 +102,28 @@ BOOST_AUTO_TEST_CASE(find) BOOST_CHECK(s.FindFirstOf("xl") == 2); } +// Check that if a std::vector is grown beyond its capacity (i.e. it has to reallocate the memory), +// it uses the move constructor of icinga::String (i.e. the underlying string storage stays the same). +BOOST_AUTO_TEST_CASE(vector_move) +{ + std::vector vec { + // std::string (which is internally used by icinga::String) has an optimization that small strings can be + // allocated inside it instead of in a separate heap allocation. In that case, the small string would still be + // copied even by the move constructor. Using sizeof() ensures that the string is long enough so that it must + // be allocated separately and can be used to test for the desired move to happen. + std::string(sizeof(String) + 1, 'A'), + }; + + void *oldAddr = vec[0].GetData().data(); + // Sanity check that the data buffer is actually allocated outside the icinga::String instance. + BOOST_CHECK(!(&vec[0] <= oldAddr && oldAddr < &vec[1])); + + // Force the vector to grow. + vec.reserve(vec.capacity() + 1); + + // If the string was moved, the location of its underlying data buffer should not have changed. + void *newAddr = vec[0].GetData().data(); + BOOST_CHECK_EQUAL(oldAddr, newAddr); +} + BOOST_AUTO_TEST_SUITE_END()