initial commit
This commit is contained in:
commit
8444e5ce55
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*-build
|
54
CMakeLists.txt
Normal file
54
CMakeLists.txt
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)
|
||||||
|
project(c++-benchmarks CXX)
|
||||||
|
|
||||||
|
include(CMakeDetermineCXXCompiler)
|
||||||
|
|
||||||
|
# default to Release
|
||||||
|
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||||
|
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE)
|
||||||
|
endif("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||||
|
|
||||||
|
|
||||||
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
|
set(EXTRA_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wno-unused-parameter -pedantic" CACHE STRING "Extra flags used by the compiler during all build types.")
|
||||||
|
else("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
|
set(EXTRA_CXX_FLAGS "" CACHE STRING "Extra flags used by the compiler during all build types.")
|
||||||
|
endif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXX_FLAGS}")
|
||||||
|
|
||||||
|
add_executable(benchmark-atomic-costs
|
||||||
|
benchmark-atomic-costs.cpp)
|
||||||
|
|
||||||
|
add_executable(benchmark-atomic-costs-pthread
|
||||||
|
benchmark-atomic-costs.cpp)
|
||||||
|
set_target_properties(benchmark-atomic-costs-pthread
|
||||||
|
PROPERTIES
|
||||||
|
COMPILE_FLAGS "-pthread"
|
||||||
|
LINK_FLAGS "-pthread")
|
||||||
|
|
||||||
|
add_executable(benchmark-shared-unique
|
||||||
|
benchmark-shared-unique.cpp
|
||||||
|
benchmark-shared-unique-impl.cpp)
|
||||||
|
|
||||||
|
add_executable(test-NULL-type
|
||||||
|
test-NULL-type.cpp)
|
||||||
|
|
||||||
|
add_executable(test-base-constr
|
||||||
|
test-base-constr.cpp)
|
||||||
|
|
||||||
|
add_executable(test-const-ref-results
|
||||||
|
test-const-ref-results.cpp)
|
||||||
|
|
||||||
|
add_executable(test-constructor-throw
|
||||||
|
test-constructor-throw.cpp)
|
||||||
|
|
||||||
|
add_executable(test-copy-shared-ptr
|
||||||
|
test-copy-shared-ptr.cpp
|
||||||
|
test-copy-shared-ptr-impl.cpp)
|
||||||
|
|
||||||
|
add_executable(test-rvalue-ref
|
||||||
|
test-rvalue-ref.cpp)
|
||||||
|
|
||||||
|
add_executable(test-smart-factory
|
||||||
|
test-smart-factory.cpp)
|
102
benchmark-atomic-costs.cpp
Normal file
102
benchmark-atomic-costs.cpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
|
||||||
|
#include "measure_time.h"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <thread>
|
||||||
|
#include <ext/concurrence.h>
|
||||||
|
|
||||||
|
#define COUNT (1u << 24)
|
||||||
|
|
||||||
|
// use "incl" for 32-bit and "incq" for 64-bit in asm below:
|
||||||
|
// use 32-bit for now: _Atomic_word should be 32-bit too;
|
||||||
|
// 64-bit is basically as fast as 32-bit if it fits in your cache
|
||||||
|
typedef std::uint32_t counting;
|
||||||
|
|
||||||
|
volatile counting __attribute__ ((aligned (64))) volatile_counter;
|
||||||
|
counting __attribute__ ((aligned (64))) simple_counter;
|
||||||
|
std::atomic<counting> __attribute__ ((aligned (64))) atomic_counter;
|
||||||
|
|
||||||
|
_Atomic_word __attribute__ ((aligned (64))) gxx_counter;
|
||||||
|
|
||||||
|
void benchmark_volatile() {
|
||||||
|
// should be the same as asm below
|
||||||
|
volatile_counter = 0;
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
++volatile_counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_asm() {
|
||||||
|
simple_counter = 0;
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
asm volatile(
|
||||||
|
"incl %0;"
|
||||||
|
: "+m"(simple_counter)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_local_atomic() {
|
||||||
|
// compiler doesn't realize no one else can read this counter and
|
||||||
|
// uses real atomic (i.e. "lock")
|
||||||
|
std::atomic<counting> local_atomic_counter;
|
||||||
|
local_atomic_counter = 0;
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
++local_atomic_counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_atomic() {
|
||||||
|
// should be the same as "lock_asm"
|
||||||
|
atomic_counter = 0;
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
++atomic_counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_lock_asm() {
|
||||||
|
simple_counter = 0;
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
asm volatile(
|
||||||
|
"lock incl %0;"
|
||||||
|
: "+m"(simple_counter)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_gxx_atomic() {
|
||||||
|
// if linked with pthread this will use "lock" same as atomic, otherwise
|
||||||
|
// it uses a simple non-volatile non-atomic add instruction
|
||||||
|
// https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_concurrency.html
|
||||||
|
// claims __atomic_add_dispatch uses a volatile counter, but this isn't
|
||||||
|
// true in gcc 4.9
|
||||||
|
gxx_counter = 0;
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
__gnu_cxx::__atomic_add_dispatch(&gxx_counter, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// std::thread fake([] { return; });
|
||||||
|
// fake.join();
|
||||||
|
|
||||||
|
std::cout << "volatile counter : ";
|
||||||
|
measure_time_with_dry_run(benchmark_volatile);
|
||||||
|
|
||||||
|
std::cout << "asm counter : ";
|
||||||
|
measure_time_with_dry_run(benchmark_asm);
|
||||||
|
|
||||||
|
std::cout << "local atomic counter: ";
|
||||||
|
measure_time_with_dry_run(benchmark_local_atomic);
|
||||||
|
|
||||||
|
std::cout << "atomic counter : ";
|
||||||
|
measure_time_with_dry_run(benchmark_atomic);
|
||||||
|
|
||||||
|
std::cout << "lock asm counter : ";
|
||||||
|
measure_time_with_dry_run(benchmark_lock_asm);
|
||||||
|
|
||||||
|
std::cout << "gxx atomic counter : ";
|
||||||
|
measure_time_with_dry_run(benchmark_gxx_atomic);
|
||||||
|
}
|
0
benchmark-results.txt
Normal file
0
benchmark-results.txt
Normal file
23
benchmark-shared-unique-impl.cpp
Normal file
23
benchmark-shared-unique-impl.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
#include "benchmark-shared-unique.h"
|
||||||
|
|
||||||
|
void* forward_raw(void* p) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::unique_ptr<size_t> forward_unique(std::unique_ptr<size_t>&& p) {
|
||||||
|
return std::move(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<size_t> forward_shared(std::shared_ptr<size_t>&& p) {
|
||||||
|
return std::move(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Large> forward_unique_large(std::unique_ptr<Large>&& p) {
|
||||||
|
return std::move(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Large> forward_shared_large(std::shared_ptr<Large>&& p) {
|
||||||
|
return std::move(p);
|
||||||
|
}
|
128
benchmark-shared-unique.cpp
Normal file
128
benchmark-shared-unique.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
|
||||||
|
#include "benchmark-shared-unique.h"
|
||||||
|
|
||||||
|
#include "measure_time.h"
|
||||||
|
#include "make_unique.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define COUNT (1u << 26)
|
||||||
|
|
||||||
|
void benchmark_forward_empty_raw() {
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
(void) forward_raw(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_forward_empty_unique() {
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
(void) forward_unique({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_forward_empty_shared() {
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
(void) forward_shared({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_forward_empty_shared_from_unique() {
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
(void) forward_shared(std::unique_ptr<size_t>{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void benchmark_forward_new_raw() {
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
size_t* p = new size_t{i};
|
||||||
|
(void) forward_raw(p);
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_forward_new_unique() {
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
(void) forward_unique(std::make_unique<size_t>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_forward_new_shared() {
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
(void) forward_shared(std::make_shared<size_t>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_forward_new_shared_from_unique() {
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
(void) forward_shared(std::make_unique<size_t>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void benchmark_forward_new_raw_large() {
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
Large* p = new Large{i};
|
||||||
|
(void) forward_raw(p);
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_forward_new_unique_large() {
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
(void) forward_unique_large(std::make_unique<Large>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_forward_new_shared_large() {
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
(void) forward_shared_large(std::make_shared<Large>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void benchmark_forward_new_shared_large_from_unique() {
|
||||||
|
for (size_t i = 0; i < COUNT; ++i) {
|
||||||
|
(void) forward_shared_large(std::make_unique<Large>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::cout << "forward empty raw : ";
|
||||||
|
measure_time(benchmark_forward_empty_raw);
|
||||||
|
|
||||||
|
std::cout << "forward empty unique : ";
|
||||||
|
measure_time(benchmark_forward_empty_unique);
|
||||||
|
|
||||||
|
std::cout << "forward empty shared : ";
|
||||||
|
measure_time(benchmark_forward_empty_shared);
|
||||||
|
|
||||||
|
std::cout << "forward empty shared from unique : ";
|
||||||
|
measure_time(benchmark_forward_empty_shared_from_unique);
|
||||||
|
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "forward new raw : ";
|
||||||
|
measure_time(benchmark_forward_new_raw);
|
||||||
|
|
||||||
|
std::cout << "forward new unique : ";
|
||||||
|
measure_time(benchmark_forward_new_unique);
|
||||||
|
|
||||||
|
std::cout << "forward new shared : ";
|
||||||
|
measure_time(benchmark_forward_new_shared);
|
||||||
|
|
||||||
|
std::cout << "forward new shared from unique : ";
|
||||||
|
measure_time(benchmark_forward_new_shared_from_unique);
|
||||||
|
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "forward new raw large : ";
|
||||||
|
measure_time(benchmark_forward_new_raw_large);
|
||||||
|
|
||||||
|
std::cout << "forward new unique large : ";
|
||||||
|
measure_time(benchmark_forward_new_unique_large);
|
||||||
|
|
||||||
|
std::cout << "forward new shared large : ";
|
||||||
|
measure_time(benchmark_forward_new_shared_large);
|
||||||
|
|
||||||
|
std::cout << "forward new shared large from unique: ";
|
||||||
|
measure_time(benchmark_forward_new_shared_large_from_unique);
|
||||||
|
}
|
16
benchmark-shared-unique.h
Normal file
16
benchmark-shared-unique.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct Large {
|
||||||
|
size_t x;
|
||||||
|
char filler[512 - sizeof(size_t)] = {};
|
||||||
|
|
||||||
|
Large(size_t x) : x(x) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
void* forward_raw(void* p);
|
||||||
|
|
||||||
|
std::unique_ptr<size_t> forward_unique(std::unique_ptr<size_t>&& p);
|
||||||
|
std::shared_ptr<size_t> forward_shared(std::shared_ptr<size_t>&& p);
|
||||||
|
|
||||||
|
std::unique_ptr<Large> forward_unique_large(std::unique_ptr<Large>&& p);
|
||||||
|
std::shared_ptr<Large> forward_shared_large(std::shared_ptr<Large>&& p);
|
36
make_unique.h
Normal file
36
make_unique.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#if __cplusplus <= 201103L
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template<class T>
|
||||||
|
struct is_unbound_array : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct is_unbound_array<T[]> : std::true_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct is_bound_array : std::false_type {};
|
||||||
|
|
||||||
|
template<class T, std::size_t N>
|
||||||
|
struct is_bound_array<T[N]> : std::true_type {};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type make_unique(Args&&... args) {
|
||||||
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
typename std::enable_if<is_unbound_array<T>::value, std::unique_ptr<T>>::type make_unique(size_t size) {
|
||||||
|
return std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]());
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class T, class... Args >
|
||||||
|
typename std::enable_if<is_bound_array<T>::value>::type make_unique( Args&&... args ) = delete;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
20
measure_time.h
Normal file
20
measure_time.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
template<typename Callable>
|
||||||
|
void measure_time(Callable&& callable) {
|
||||||
|
using namespace std::chrono;
|
||||||
|
steady_clock::time_point t_start = steady_clock::now();
|
||||||
|
callable();
|
||||||
|
duration<double> time_span = duration_cast<duration<double>>(steady_clock::now() - t_start);
|
||||||
|
|
||||||
|
std::cout << "took " << time_span.count() << " seconds\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Callable>
|
||||||
|
void measure_time_with_dry_run(Callable&& callable) {
|
||||||
|
callable();
|
||||||
|
measure_time(std::forward<Callable>(callable));
|
||||||
|
}
|
15
test-NULL-type.cpp
Normal file
15
test-NULL-type.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
#include "type_name.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto o = NULL;
|
||||||
|
int* n(reinterpret_cast<int*>(o));
|
||||||
|
// auto n = std::make_pair(0, (intptr_t) NULL);
|
||||||
|
std::cout << "decltype(n) is " << TYPE_NAME(n) << '\n';
|
||||||
|
auto p = std::make_pair(std::ref(o), nullptr);
|
||||||
|
std::cout << "decltype(p) is " << TYPE_NAME(p) << '\n';
|
||||||
|
}
|
30
test-base-constr.cpp
Normal file
30
test-base-constr.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define L(s) std::cerr << s << "\n"
|
||||||
|
|
||||||
|
struct A {
|
||||||
|
A() { L("A::A()"); }
|
||||||
|
A(A&&) { L("A::A(A&&)"); }
|
||||||
|
A(const A&) { L("A::A(const A&)"); }
|
||||||
|
~A() { L("A::~A()"); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct B: A {
|
||||||
|
B() { L("B::B()"); }
|
||||||
|
B(A&&) { L("B::B(A&&)"); }
|
||||||
|
//B(B&&) { L("B::B(B&&)"); }
|
||||||
|
B(const A&) { L("B::B(const A&)"); }
|
||||||
|
// B(const B&) { L("B::B(const B&)"); }
|
||||||
|
~B() { L("B::~B()"); }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
L("A a1;");
|
||||||
|
A a1;
|
||||||
|
L("B b1(a1);");
|
||||||
|
B b1(a1);
|
||||||
|
L("B b1(b1);");
|
||||||
|
B b2(static_cast<A&>(b1));
|
||||||
|
return 0;
|
||||||
|
}
|
22
test-const-ref-results.cpp
Normal file
22
test-const-ref-results.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class C {
|
||||||
|
public:
|
||||||
|
int valid;
|
||||||
|
C() : valid(1) { }
|
||||||
|
~C() { valid = 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* some "random" comparison, doesn't matter */
|
||||||
|
bool operator<(C const& a, C const& b) {
|
||||||
|
return reinterpret_cast<uintptr_t>(&a) < reinterpret_cast<uintptr_t>(&b);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto const& m =
|
||||||
|
// std::max(*std::make_shared<C>(), *std::make_shared<C>());
|
||||||
|
std::max(C(), C());
|
||||||
|
std::cout << m.valid << "\n";
|
||||||
|
}
|
35
test-constructor-throw.cpp
Normal file
35
test-constructor-throw.cpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "make_unique.h"
|
||||||
|
|
||||||
|
struct C {
|
||||||
|
private:
|
||||||
|
struct private_type { };
|
||||||
|
C(private_type) { }
|
||||||
|
int *m_i = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
C() : C(private_type()) { m_i = new int; throw std::exception(); }
|
||||||
|
~C() { delete m_i; }
|
||||||
|
C(C const&) = delete;
|
||||||
|
C& operator=(C const&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct D {
|
||||||
|
std::unique_ptr<int> m_i;
|
||||||
|
D() : m_i(std::make_unique<int>()) { m_i = std::make_unique<int>(); throw std::exception(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
try {
|
||||||
|
C c;
|
||||||
|
} catch (...) { }
|
||||||
|
|
||||||
|
auto a = std::make_unique<int[]>(10);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
10
test-copy-shared-ptr-impl.cpp
Normal file
10
test-copy-shared-ptr-impl.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
void copy_ptr(std::shared_ptr<int>& a, std::shared_ptr<int> const& b) {
|
||||||
|
a = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void move_ptr(std::shared_ptr<int>& a, std::shared_ptr<int>& b) {
|
||||||
|
a = std::move(b);
|
||||||
|
}
|
8
test-copy-shared-ptr.cpp
Normal file
8
test-copy-shared-ptr.cpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
void copy_ptr(std::shared_ptr<int>& a, std::shared_ptr<int> const& b);
|
||||||
|
void move_ptr(std::shared_ptr<int>& a, std::shared_ptr<int>& b);
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
}
|
23
test-rvalue-ref.cpp
Normal file
23
test-rvalue-ref.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
#include "type_name.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
void f(const int&) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#define T(v) std::cout << #v << ": " << TYPE_NAME(v) << "\n"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto&& i = 1;
|
||||||
|
auto& ri = i;
|
||||||
|
auto const& x = std::move(ri);
|
||||||
|
decltype(ri) y = ri;
|
||||||
|
f(i);
|
||||||
|
// f(std::forward(i));
|
||||||
|
T(i);
|
||||||
|
T(ri);
|
||||||
|
T(x);
|
||||||
|
T(y);
|
||||||
|
return 0;
|
||||||
|
}
|
118
test-smart-factory.cpp
Normal file
118
test-smart-factory.cpp
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
class C {
|
||||||
|
protected:
|
||||||
|
struct Protected {
|
||||||
|
private:
|
||||||
|
Protected() {};
|
||||||
|
public:
|
||||||
|
static Protected make() { return { }; }
|
||||||
|
};
|
||||||
|
int m_x;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Private {
|
||||||
|
private:
|
||||||
|
Private() {};
|
||||||
|
public:
|
||||||
|
static Private make() { return { }; }
|
||||||
|
};
|
||||||
|
int m_y;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/* private constructor: */
|
||||||
|
C(Private, int x, int y) : m_x(x), m_y(y) { }
|
||||||
|
/* protected constructor: */
|
||||||
|
C(Protected, int x) : C(Private::make(), x, 2*x) { }
|
||||||
|
|
||||||
|
void leak_private_type(Private) { }
|
||||||
|
|
||||||
|
static std::unique_ptr<C> Create(int x) {
|
||||||
|
return std::unique_ptr<C>(new C(Private::make(), x, 2*x));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class D : public C {
|
||||||
|
private:
|
||||||
|
struct Private { };
|
||||||
|
public:
|
||||||
|
D(Private&, int x) : C(Protected::make(), x) { }
|
||||||
|
|
||||||
|
static std::shared_ptr<D> Create(int x) {
|
||||||
|
Private p;
|
||||||
|
return std::make_shared<D>(p, 4*x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class A {
|
||||||
|
struct this_is_private {
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit A(const this_is_private &, int) {}
|
||||||
|
|
||||||
|
static ::std::shared_ptr<A> create(int x) {
|
||||||
|
return ::std::make_shared<A>(this_is_private{}, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
A(const A &) = delete;
|
||||||
|
const A &operator =(const A &) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
::std::shared_ptr<A> foo(int x)
|
||||||
|
{
|
||||||
|
return A::create(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* usage: decltype(return_args(&Class::memberfunction)) */
|
||||||
|
template<typename Base, typename Result, typename... Args>
|
||||||
|
std::tuple<Args...> return_args(Result (Base::*func)(Args...));
|
||||||
|
|
||||||
|
/* usage: decltype(result_of(&Class::memberfunction)) */
|
||||||
|
template<typename Base, typename Result, typename... Args>
|
||||||
|
Result result_of(Result (Base::*func)(Args...));
|
||||||
|
|
||||||
|
/* usage: decay_tuple_element<0, decltype(return_args(&Class::memberfunction))> */
|
||||||
|
template <size_t i, typename Tuple>
|
||||||
|
using decay_tuple_element = typename std::decay<typename std::tuple_element<i, Tuple>::type>::type;
|
||||||
|
|
||||||
|
|
||||||
|
struct _is_static_castable_impl
|
||||||
|
{
|
||||||
|
template<typename _From, typename _To, typename = decltype(static_cast<_To>(std::declval<_From>()))>
|
||||||
|
static std::true_type __test(int);
|
||||||
|
|
||||||
|
template<typename, typename>
|
||||||
|
static std::false_type __test(...);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _From, typename _To>
|
||||||
|
struct is_static_castable
|
||||||
|
: public _is_static_castable_impl
|
||||||
|
{
|
||||||
|
typedef decltype(__test<_From, _To>(0)) type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename _From, typename _To>
|
||||||
|
using is_static_castable_t = typename is_static_castable<_From, _To>::type;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto c = C::Create(0);
|
||||||
|
auto d = D::Create(0);
|
||||||
|
|
||||||
|
typedef decay_tuple_element<0, decltype(return_args(&C::leak_private_type))> Private;
|
||||||
|
Private::make();
|
||||||
|
|
||||||
|
|
||||||
|
auto a1 = foo(0);
|
||||||
|
auto a2 = std::shared_ptr<A>(new A({}, 0));
|
||||||
|
|
||||||
|
// C c1({}, 0, 0);
|
||||||
|
}
|
38
type_name.h
Normal file
38
type_name.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <typeinfo>
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
# include <cxxabi.h>
|
||||||
|
#endif
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
std::string
|
||||||
|
type_name()
|
||||||
|
{
|
||||||
|
typedef typename std::remove_reference<T>::type TR;
|
||||||
|
std::unique_ptr<char, void(*)(void*)> own
|
||||||
|
(
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
abi::__cxa_demangle(typeid(TR).name(), nullptr, nullptr, nullptr),
|
||||||
|
#else
|
||||||
|
nullptr,
|
||||||
|
#endif
|
||||||
|
std::free
|
||||||
|
);
|
||||||
|
std::string r = own != nullptr ? own.get() : typeid(TR).name();
|
||||||
|
if (std::is_const<TR>::value)
|
||||||
|
r += " const";
|
||||||
|
if (std::is_volatile<TR>::value)
|
||||||
|
r += " volatile";
|
||||||
|
if (std::is_lvalue_reference<T>::value)
|
||||||
|
r += "&";
|
||||||
|
else if (std::is_rvalue_reference<T>::value)
|
||||||
|
r += "&&";
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TYPE_NAME(p) (type_name<decltype(p)>())
|
Loading…
Reference in New Issue
Block a user