Last active
February 29, 2016 07:37
-
-
Save Masstronaut/91ba8711a293dd35596c to your computer and use it in GitHub Desktop.
Test code for determining the behavior of Return Value Optimization in various situations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This file is to test the behavior of various compilers' return value optimizations (RVO) in different scenarios | |
#include <iostream> | |
#include <cstdlib> // std::rand | |
#include <array> | |
#include <utility> // std::move | |
// This class is small enough to fit in a register, and should be a simple target for return value optimization | |
class SmallObject { | |
public: | |
static unsigned instance_count; | |
// default constructor | |
SmallObject() { | |
++instance_count; | |
std::cout << "SmallObject default constructed.\n"; | |
} | |
// copy constructor | |
SmallObject(const SmallObject &rhs) | |
: m_var(rhs.m_var) { | |
++instance_count; | |
std::cout << "SmallObject copy constructed.\n"; | |
} | |
// move constructor | |
SmallObject(SmallObject &&rhs) | |
: m_var(rhs.m_var) { | |
rhs.m_var = -1; | |
++instance_count; | |
std::cout << "SmallObject move constructed.\n"; | |
} | |
// default destructor | |
~SmallObject() { | |
--instance_count; | |
std::cout << "SmallObject destructed.\n"; | |
} | |
// assignment operator. We do nothing as both instances already existed | |
SmallObject& operator=(const SmallObject &rhs) { | |
m_var = rhs.m_var; | |
std::cout << "SmallObject assigned.\n"; | |
} | |
// This function will perform transformations on the data in an attempt to confuse the optimizer | |
void do_something_complicated() { | |
m_var = std::rand() % ( RAND_MAX / 2 ); | |
if ( m_var < 1000 ) | |
m_var = 0; | |
else if (m_var < 10000) | |
m_var = 1; | |
} | |
private: | |
int m_var{0}; | |
}; | |
// This class is too large to fit in a register, and should require more work to have good RVO. | |
class LargeObject { | |
public: | |
static unsigned instance_count; | |
// default constructor | |
LargeObject() { | |
++instance_count; | |
std::cout << "LargeObject default constructed.\n"; | |
} | |
// copy constructor | |
LargeObject(const LargeObject &rhs) { | |
++instance_count; | |
std::cout << "LargeObject copy constructed.\n"; | |
} | |
// move constructor | |
LargeObject(LargeObject &&rhs) | |
: m_data(std::move(rhs.m_data)) { | |
++instance_count; | |
std::cout << "LargeObject move constructed.\n"; | |
} | |
// default destructor | |
~LargeObject() { | |
--instance_count; | |
std::cout << "LargeObject destructed.\n"; | |
} | |
// assignment operator. We do nothing as both instances already existed | |
LargeObject& operator=(const LargeObject &rhs) { | |
std::cout << "LargeObject assigned.\n"; | |
} | |
// This function will perform transformations on the data in an attempt to confuse the optimizer | |
void do_something_complicated(){ | |
for(auto &&it : m_data){ | |
it = std::rand(); | |
} | |
} | |
private: | |
std::array<unsigned, 256> m_data; | |
}; | |
unsigned LargeObject::instance_count{ 0 }; | |
unsigned SmallObject::instance_count{ 0 }; | |
// Simple construction | |
SmallObject create_small_object_simple(){ | |
return SmallObject(); | |
} | |
void test_small_simple() { | |
SmallObject so = create_small_object_simple(); | |
} | |
LargeObject create_large_object_simple(){ | |
return LargeObject(); | |
} | |
void test_large_simple() { | |
LargeObject lo = create_large_object_simple(); | |
} | |
// Construction and manipulation | |
SmallObject create_small_object_complex(){ | |
SmallObject so; | |
so.do_something_complicated(); | |
return so; | |
} | |
void test_small_complex() { | |
SmallObject so = create_small_object_complex(); | |
} | |
LargeObject create_large_object_complex(){ | |
LargeObject lo; | |
lo.do_something_complicated(); | |
return lo; | |
} | |
void test_large_complex() { | |
LargeObject lo = create_large_object_complex(); | |
} | |
// Simple construction with forced move semantics | |
SmallObject move_small_object_simple() { | |
return std::move(SmallObject()); | |
} | |
void test_small_simple_move() { | |
SmallObject so = move_small_object_simple(); | |
} | |
LargeObject move_large_object_simple() { | |
return std::move(LargeObject()); | |
} | |
void test_large_simple_move() { | |
LargeObject lo = move_large_object_simple(); | |
} | |
// Construction and manipulation with forced move semantics | |
SmallObject move_small_object_complex() { | |
SmallObject so; | |
so.do_something_complicated(); | |
return std::move(so); | |
} | |
void test_small_complex_move() { | |
SmallObject so = move_small_object_complex(); | |
} | |
LargeObject move_large_object_complex() { | |
LargeObject lo; | |
lo.do_something_complicated(); | |
return std::move(lo); | |
} | |
void test_large_complex_move() { | |
LargeObject lo = move_large_object_complex(); | |
} | |
int main() { | |
std::cout << "Testing simple small object RVO: " << std::endl; | |
test_small_simple(); | |
std::cout << std::endl; | |
std::cout << "Testing simple large object RVO: " << std::endl; | |
test_large_simple(); | |
std::cout << std::endl; | |
std::cout << "Testing complex small object RVO: " << std::endl; | |
test_small_complex(); | |
std::cout << std::endl; | |
std::cout << "Testing complex large object RVO: " << std::endl; | |
test_large_complex(); | |
std::cout << std::endl; | |
std::cout << "Testing simple small object forced move semantics RVO: " << std::endl; | |
test_small_simple_move(); | |
std::cout << std::endl; | |
std::cout << "Testing simple large object forced move semantics RVO: " << std::endl; | |
test_large_simple_move(); | |
std::cout << std::endl; | |
std::cout << "Testing complex small object forced move semantics RVO: " << std::endl; | |
test_small_complex_move(); | |
std::cout << std::endl; | |
std::cout << "Testing complex large object forced move semantics RVO: " << std::endl; | |
test_large_complex_move(); | |
std::cout << std::endl; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment