mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-13 09:03:54 +00:00
Merge pull request #324 from jagerman/example-constructor-tracking
Improve constructor/destructor tracking
This commit is contained in:
commit
f4f2afb6c9
@ -60,9 +60,6 @@ foreach(CompilerFlag ${CompilerFlags})
|
|||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
set(RUN_TEST ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/run_test.py)
|
set(RUN_TEST ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/run_test.py)
|
||||||
if(MSVC OR CMAKE_CXX_COMPILER_ID MATCHES "Intel")
|
|
||||||
set(RUN_TEST ${RUN_TEST} --relaxed)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
foreach(VALUE ${PYBIND11_EXAMPLES})
|
foreach(VALUE ${PYBIND11_EXAMPLES})
|
||||||
string(REGEX REPLACE "^(.+).cpp$" "\\1" EXAMPLE_NAME "${VALUE}")
|
string(REGEX REPLACE "^(.+).cpp$" "\\1" EXAMPLE_NAME "${VALUE}")
|
||||||
|
243
example/constructor-stats.h
Normal file
243
example/constructor-stats.h
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
example/constructor-stats.h -- framework for printing and tracking object
|
||||||
|
instance lifetimes in example/test code.
|
||||||
|
|
||||||
|
Copyright (c) 2016 Jason Rhinelander <jason@imaginary.ca>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
This header provides a few useful tools for writing examples or tests that want to check and/or
|
||||||
|
display object instance lifetimes. It requires that you include this header and add the following
|
||||||
|
function calls to constructors:
|
||||||
|
|
||||||
|
class MyClass {
|
||||||
|
MyClass() { ...; print_default_created(this); }
|
||||||
|
~MyClass() { ...; print_destroyed(this); }
|
||||||
|
MyClass(const MyClass &c) { ...; print_copy_created(this); }
|
||||||
|
MyClass(MyClass &&c) { ...; print_move_created(this); }
|
||||||
|
MyClass(int a, int b) { ...; print_created(this, a, b); }
|
||||||
|
MyClass &operator=(const MyClass &c) { ...; print_copy_assigned(this); }
|
||||||
|
MyClass &operator=(MyClass &&c) { ...; print_move_assigned(this); }
|
||||||
|
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
You can find various examples of these in several of the existing example .cpp files. (Of course
|
||||||
|
you don't need to add any of the above constructors/operators that you don't actually have, except
|
||||||
|
for the destructor).
|
||||||
|
|
||||||
|
Each of these will print an appropriate message such as:
|
||||||
|
|
||||||
|
### MyClass @ 0x2801910 created via default constructor
|
||||||
|
### MyClass @ 0x27fa780 created 100 200
|
||||||
|
### MyClass @ 0x2801910 destroyed
|
||||||
|
### MyClass @ 0x27fa780 destroyed
|
||||||
|
|
||||||
|
You can also include extra arguments (such as the 100, 200 in the output above, coming from the
|
||||||
|
value constructor) for all of the above methods which will be included in the output.
|
||||||
|
|
||||||
|
For testing, each of these also keeps track the created instances and allows you to check how many
|
||||||
|
of the various constructors have been invoked from the Python side via code such as:
|
||||||
|
|
||||||
|
from example import ConstructorStats
|
||||||
|
cstats = ConstructorStats.get(MyClass)
|
||||||
|
print(cstats.alive())
|
||||||
|
print(cstats.default_constructions)
|
||||||
|
|
||||||
|
Note that `.alive()` should usually be the first thing you call as it invokes Python's garbage
|
||||||
|
collector to actually destroy objects that aren't yet referenced.
|
||||||
|
|
||||||
|
For everything except copy and move constructors and destructors, any extra values given to the
|
||||||
|
print_...() function is stored in a class-specific values list which you can retrieve and inspect
|
||||||
|
from the ConstructorStats instance `.values()` method.
|
||||||
|
|
||||||
|
In some cases, when you need to track instances of a C++ class not registered with pybind11, you
|
||||||
|
need to add a function returning the ConstructorStats for the C++ class; this can be done with:
|
||||||
|
|
||||||
|
m.def("get_special_cstats", &ConstructorStats::get<SpecialClass>, py::return_value_policy::reference_internal)
|
||||||
|
|
||||||
|
Finally, you can suppress the output messages, but keep the constructor tracking (for
|
||||||
|
inspection/testing in python) by using the functions with `print_` replaced with `track_` (e.g.
|
||||||
|
`track_copy_created(this)`).
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "example.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <list>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
class ConstructorStats {
|
||||||
|
protected:
|
||||||
|
std::unordered_map<void*, int> _instances; // Need a map rather than set because members can shared address with parents
|
||||||
|
std::list<std::string> _values; // Used to track values (e.g. of value constructors)
|
||||||
|
public:
|
||||||
|
int default_constructions = 0;
|
||||||
|
int copy_constructions = 0;
|
||||||
|
int move_constructions = 0;
|
||||||
|
int copy_assignments = 0;
|
||||||
|
int move_assignments = 0;
|
||||||
|
|
||||||
|
void copy_created(void *inst) {
|
||||||
|
created(inst);
|
||||||
|
copy_constructions++;
|
||||||
|
}
|
||||||
|
void move_created(void *inst) {
|
||||||
|
created(inst);
|
||||||
|
move_constructions++;
|
||||||
|
}
|
||||||
|
void default_created(void *inst) {
|
||||||
|
created(inst);
|
||||||
|
default_constructions++;
|
||||||
|
}
|
||||||
|
void created(void *inst) {
|
||||||
|
++_instances[inst];
|
||||||
|
};
|
||||||
|
void destroyed(void *inst) {
|
||||||
|
if (--_instances[inst] < 0)
|
||||||
|
throw std::runtime_error("cstats.destroyed() called with unknown instance; potential double-destruction or a missing cstats.created()");
|
||||||
|
}
|
||||||
|
|
||||||
|
int alive() {
|
||||||
|
// Force garbage collection to ensure any pending destructors are invoked:
|
||||||
|
py::module::import("gc").attr("collect").operator py::object()();
|
||||||
|
int total = 0;
|
||||||
|
for (const auto &p : _instances) if (p.second > 0) total += p.second;
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
void value() {} // Recursion terminator
|
||||||
|
// Takes one or more values, converts them to strings, then stores them.
|
||||||
|
template <typename T, typename... Tmore> void value(const T &v, Tmore &&...args) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << v;
|
||||||
|
_values.push_back(oss.str());
|
||||||
|
value(std::forward<Tmore>(args)...);
|
||||||
|
}
|
||||||
|
py::list values() {
|
||||||
|
py::list l;
|
||||||
|
for (const auto &v : _values) l.append(py::cast(v));
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets constructor stats from a C++ type index
|
||||||
|
static ConstructorStats& get(std::type_index type) {
|
||||||
|
static std::unordered_map<std::type_index, ConstructorStats> all_cstats;
|
||||||
|
return all_cstats[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets constructor stats from a C++ type
|
||||||
|
template <typename T> static ConstructorStats& get() {
|
||||||
|
return get(typeid(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets constructor stats from a Python class
|
||||||
|
static ConstructorStats& get(py::object class_) {
|
||||||
|
auto &internals = py::detail::get_internals();
|
||||||
|
const std::type_index *t1 = nullptr, *t2 = nullptr;
|
||||||
|
try {
|
||||||
|
auto *type_info = internals.registered_types_py.at(class_.ptr());
|
||||||
|
for (auto &p : internals.registered_types_cpp) {
|
||||||
|
if (p.second == type_info) {
|
||||||
|
if (t1) {
|
||||||
|
t2 = &p.first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
t1 = &p.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::out_of_range) {}
|
||||||
|
if (!t1) throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
|
||||||
|
auto &cs1 = get(*t1);
|
||||||
|
// If we have both a t1 and t2 match, one is probably the trampoline class; return whichever
|
||||||
|
// has more constructions (typically one or the other will be 0)
|
||||||
|
if (t2) {
|
||||||
|
auto &cs2 = get(*t2);
|
||||||
|
int cs1_total = cs1.default_constructions + cs1.copy_constructions + cs1.move_constructions + (int) cs1._values.size();
|
||||||
|
int cs2_total = cs2.default_constructions + cs2.copy_constructions + cs2.move_constructions + (int) cs2._values.size();
|
||||||
|
if (cs2_total > cs1_total) return cs2;
|
||||||
|
}
|
||||||
|
return cs1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// To track construction/destruction, you need to call these methods from the various
|
||||||
|
// constructors/operators. The ones that take extra values record the given values in the
|
||||||
|
// constructor stats values for later inspection.
|
||||||
|
template <class T> void track_copy_created(T *inst) { ConstructorStats::get<T>().copy_created(inst); }
|
||||||
|
template <class T> void track_move_created(T *inst) { ConstructorStats::get<T>().move_created(inst); }
|
||||||
|
template <class T, typename... Values> void track_copy_assigned(T *, Values &&...values) {
|
||||||
|
auto &cst = ConstructorStats::get<T>();
|
||||||
|
cst.copy_assignments++;
|
||||||
|
cst.value(std::forward<Values>(values)...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void track_move_assigned(T *, Values &&...values) {
|
||||||
|
auto &cst = ConstructorStats::get<T>();
|
||||||
|
cst.move_assignments++;
|
||||||
|
cst.value(std::forward<Values>(values)...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void track_default_created(T *inst, Values &&...values) {
|
||||||
|
auto &cst = ConstructorStats::get<T>();
|
||||||
|
cst.default_created(inst);
|
||||||
|
cst.value(std::forward<Values>(values)...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void track_created(T *inst, Values &&...values) {
|
||||||
|
auto &cst = ConstructorStats::get<T>();
|
||||||
|
cst.created(inst);
|
||||||
|
cst.value(std::forward<Values>(values)...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void track_destroyed(T *inst) {
|
||||||
|
ConstructorStats::get<T>().destroyed(inst);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void track_values(T *, Values &&...values) {
|
||||||
|
ConstructorStats::get<T>().value(std::forward<Values>(values)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void print_constr_details_more() { std::cout << std::endl; }
|
||||||
|
template <typename Head, typename... Tail> void print_constr_details_more(const Head &head, Tail &&...tail) {
|
||||||
|
std::cout << " " << head;
|
||||||
|
print_constr_details_more(std::forward<Tail>(tail)...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Output> void print_constr_details(T *inst, const std::string &action, Output &&...output) {
|
||||||
|
std::cout << "### " << py::type_id<T>() << " @ " << inst << " " << action;
|
||||||
|
print_constr_details_more(std::forward<Output>(output)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verbose versions of the above:
|
||||||
|
template <class T, typename... Values> void print_copy_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
|
||||||
|
print_constr_details(inst, "created via copy constructor", values...);
|
||||||
|
track_copy_created(inst);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_move_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
|
||||||
|
print_constr_details(inst, "created via move constructor", values...);
|
||||||
|
track_move_created(inst);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_copy_assigned(T *inst, Values &&...values) {
|
||||||
|
print_constr_details(inst, "assigned via copy assignment", values...);
|
||||||
|
track_copy_assigned(inst, values...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_move_assigned(T *inst, Values &&...values) {
|
||||||
|
print_constr_details(inst, "assigned via move assignment", values...);
|
||||||
|
track_move_assigned(inst, values...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_default_created(T *inst, Values &&...values) {
|
||||||
|
print_constr_details(inst, "created via default constructor", values...);
|
||||||
|
track_default_created(inst, values...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_created(T *inst, Values &&...values) {
|
||||||
|
print_constr_details(inst, "created", values...);
|
||||||
|
track_created(inst, values...);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_destroyed(T *inst, Values &&...values) { // Prints but doesn't store given values
|
||||||
|
print_constr_details(inst, "destroyed", values...);
|
||||||
|
track_destroyed(inst);
|
||||||
|
}
|
||||||
|
template <class T, typename... Values> void print_values(T *inst, Values &&...values) {
|
||||||
|
print_constr_details(inst, ":", values...);
|
||||||
|
track_values(inst, values...);
|
||||||
|
}
|
||||||
|
|
@ -8,35 +8,36 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "example.h"
|
#include "example.h"
|
||||||
|
#include "constructor-stats.h"
|
||||||
|
|
||||||
class Matrix {
|
class Matrix {
|
||||||
public:
|
public:
|
||||||
Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) {
|
Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) {
|
||||||
std::cout << "Value constructor: Creating a " << rows << "x" << cols << " matrix " << std::endl;
|
print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
m_data = new float[rows*cols];
|
m_data = new float[rows*cols];
|
||||||
memset(m_data, 0, sizeof(float) * rows * cols);
|
memset(m_data, 0, sizeof(float) * rows * cols);
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
|
Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
|
||||||
std::cout << "Copy constructor: Creating a " << m_rows << "x" << m_cols << " matrix " << std::endl;
|
print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
m_data = new float[m_rows * m_cols];
|
m_data = new float[m_rows * m_cols];
|
||||||
memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols);
|
memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols);
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
|
Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
|
||||||
std::cout << "Move constructor: Creating a " << m_rows << "x" << m_cols << " matrix " << std::endl;
|
print_move_created(this);
|
||||||
s.m_rows = 0;
|
s.m_rows = 0;
|
||||||
s.m_cols = 0;
|
s.m_cols = 0;
|
||||||
s.m_data = nullptr;
|
s.m_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
~Matrix() {
|
~Matrix() {
|
||||||
std::cout << "Freeing a " << m_rows << "x" << m_cols << " matrix " << std::endl;
|
print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
delete[] m_data;
|
delete[] m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix &operator=(const Matrix &s) {
|
Matrix &operator=(const Matrix &s) {
|
||||||
std::cout << "Assignment operator : Creating a " << s.m_rows << "x" << s.m_cols << " matrix " << std::endl;
|
print_copy_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
delete[] m_data;
|
delete[] m_data;
|
||||||
m_rows = s.m_rows;
|
m_rows = s.m_rows;
|
||||||
m_cols = s.m_cols;
|
m_cols = s.m_cols;
|
||||||
@ -46,7 +47,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Matrix &operator=(Matrix &&s) {
|
Matrix &operator=(Matrix &&s) {
|
||||||
std::cout << "Move assignment operator : Creating a " << s.m_rows << "x" << s.m_cols << " matrix " << std::endl;
|
print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
if (&s != this) {
|
if (&s != this) {
|
||||||
delete[] m_data;
|
delete[] m_data;
|
||||||
m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data;
|
m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data;
|
||||||
@ -111,5 +112,6 @@ void init_ex_buffers(py::module &m) {
|
|||||||
{ sizeof(float) * m.rows(), /* Strides (in bytes) for each index */
|
{ sizeof(float) * m.rows(), /* Strides (in bytes) for each index */
|
||||||
sizeof(float) }
|
sizeof(float) }
|
||||||
);
|
);
|
||||||
});
|
})
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
@ -30,3 +30,16 @@ for i in range(m4.rows()):
|
|||||||
for j in range(m4.cols()):
|
for j in range(m4.cols()):
|
||||||
print(m4[i, j], end = ' ')
|
print(m4[i, j], end = ' ')
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
from example import ConstructorStats
|
||||||
|
cstats = ConstructorStats.get(Matrix)
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
m = m4 = None
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
m2 = None # m2 holds an m reference
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
print("Constructor values:", cstats.values())
|
||||||
|
print("Copy constructions:", cstats.copy_constructions)
|
||||||
|
#print("Move constructions:", cstats.move_constructions >= 0) # Don't invoke any
|
||||||
|
print("Copy assignments:", cstats.copy_assignments)
|
||||||
|
print("Move assignments:", cstats.move_assignments)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Value constructor: Creating a 5x5 matrix
|
### Matrix @ 0x1df1920 created 5x5 matrix
|
||||||
0.0
|
0.0
|
||||||
4.0
|
4.0
|
||||||
[[ 0. 0. 0. 0. 0.]
|
[[ 0. 0. 0. 0. 0.]
|
||||||
@ -10,8 +10,15 @@ Value constructor: Creating a 5x5 matrix
|
|||||||
5.0
|
5.0
|
||||||
[[ 1. 2. 3.]
|
[[ 1. 2. 3.]
|
||||||
[ 4. 5. 6.]]
|
[ 4. 5. 6.]]
|
||||||
Value constructor: Creating a 2x3 matrix
|
### Matrix @ 0x1fa8cf0 created 2x3 matrix
|
||||||
1.0 2.0 3.0
|
1.0 2.0 3.0
|
||||||
4.0 5.0 6.0
|
4.0 5.0 6.0
|
||||||
Freeing a 2x3 matrix
|
Instances not destroyed: 2
|
||||||
Freeing a 5x5 matrix
|
### Matrix @ 0x1fa8cf0 destroyed 2x3 matrix
|
||||||
|
Instances not destroyed: 1
|
||||||
|
### Matrix @ 0x1df1920 destroyed 5x5 matrix
|
||||||
|
Instances not destroyed: 0
|
||||||
|
Constructor values: ['5x5 matrix', '2x3 matrix']
|
||||||
|
Copy constructions: 0
|
||||||
|
Copy assignments: 0
|
||||||
|
Move assignments: 0
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "example.h"
|
#include "example.h"
|
||||||
|
#include "constructor-stats.h"
|
||||||
#include <pybind11/functional.h>
|
#include <pybind11/functional.h>
|
||||||
|
|
||||||
|
|
||||||
@ -57,6 +58,21 @@ void test_dummy_function(const std::function<int(int)> &f) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Payload {
|
||||||
|
Payload() {
|
||||||
|
print_default_created(this);
|
||||||
|
}
|
||||||
|
~Payload() {
|
||||||
|
print_destroyed(this);
|
||||||
|
}
|
||||||
|
Payload(const Payload &) {
|
||||||
|
print_copy_created(this);
|
||||||
|
}
|
||||||
|
Payload(Payload &&) {
|
||||||
|
print_move_created(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void init_ex_callbacks(py::module &m) {
|
void init_ex_callbacks(py::module &m) {
|
||||||
m.def("test_callback1", &test_callback1);
|
m.def("test_callback1", &test_callback1);
|
||||||
m.def("test_callback2", &test_callback2);
|
m.def("test_callback2", &test_callback2);
|
||||||
@ -66,21 +82,6 @@ void init_ex_callbacks(py::module &m) {
|
|||||||
|
|
||||||
/* Test cleanup of lambda closure */
|
/* Test cleanup of lambda closure */
|
||||||
|
|
||||||
struct Payload {
|
|
||||||
Payload() {
|
|
||||||
std::cout << "Payload constructor" << std::endl;
|
|
||||||
}
|
|
||||||
~Payload() {
|
|
||||||
std::cout << "Payload destructor" << std::endl;
|
|
||||||
}
|
|
||||||
Payload(const Payload &) {
|
|
||||||
std::cout << "Payload copy constructor" << std::endl;
|
|
||||||
}
|
|
||||||
Payload(Payload &&) {
|
|
||||||
std::cout << "Payload move constructor" << std::endl;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
m.def("test_cleanup", []() -> std::function<void(void)> {
|
m.def("test_cleanup", []() -> std::function<void(void)> {
|
||||||
Payload p;
|
Payload p;
|
||||||
|
|
||||||
@ -94,4 +95,6 @@ void init_ex_callbacks(py::module &m) {
|
|||||||
m.def("dummy_function2", &dummy_function2);
|
m.def("dummy_function2", &dummy_function2);
|
||||||
m.def("roundtrip", &roundtrip);
|
m.def("roundtrip", &roundtrip);
|
||||||
m.def("test_dummy_function", &test_dummy_function);
|
m.def("test_dummy_function", &test_dummy_function);
|
||||||
|
// Export the payload constructor statistics for testing purposes:
|
||||||
|
m.def("payload_cstats", &ConstructorStats::get<Payload>);
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,12 @@ print("func(number=43) = %i" % f(number=43))
|
|||||||
|
|
||||||
test_cleanup()
|
test_cleanup()
|
||||||
|
|
||||||
|
from example import payload_cstats
|
||||||
|
cstats = payload_cstats()
|
||||||
|
print("Payload instances not destroyed:", cstats.alive())
|
||||||
|
print("Copy constructions:", cstats.copy_constructions)
|
||||||
|
print("Move constructions:", cstats.move_constructions >= 1)
|
||||||
|
|
||||||
from example import dummy_function
|
from example import dummy_function
|
||||||
from example import dummy_function2
|
from example import dummy_function2
|
||||||
from example import test_dummy_function
|
from example import test_dummy_function
|
||||||
|
@ -7,7 +7,7 @@ Molly is a dog
|
|||||||
Woof!
|
Woof!
|
||||||
The following error is expected: Incompatible function arguments. The following argument types are supported:
|
The following error is expected: Incompatible function arguments. The following argument types are supported:
|
||||||
1. (arg0: example.Dog) -> None
|
1. (arg0: example.Dog) -> None
|
||||||
Invoked with: <example.Pet object at 0>
|
Invoked with: <example.Pet object at 0x7ffaf4b00db0>
|
||||||
Callback function 1 called!
|
Callback function 1 called!
|
||||||
False
|
False
|
||||||
Callback function 2 called : Hello, x, True, 5
|
Callback function 2 called : Hello, x, True, 5
|
||||||
@ -19,12 +19,15 @@ False
|
|||||||
func(43) = 44
|
func(43) = 44
|
||||||
func(43) = 44
|
func(43) = 44
|
||||||
func(number=43) = 44
|
func(number=43) = 44
|
||||||
Payload constructor
|
### Payload @ 0x7ffdcee09c80 created via default constructor
|
||||||
Payload copy constructor
|
### Payload @ 0x7ffdcee09c88 created via copy constructor
|
||||||
Payload move constructor
|
### Payload @ 0xb54500 created via move constructor
|
||||||
Payload destructor
|
### Payload @ 0x7ffdcee09c88 destroyed
|
||||||
Payload destructor
|
### Payload @ 0x7ffdcee09c80 destroyed
|
||||||
Payload destructor
|
### Payload @ 0xb54500 destroyed
|
||||||
|
Payload instances not destroyed: 0
|
||||||
|
Copy constructions: 1
|
||||||
|
Move constructions: True
|
||||||
argument matches dummy_function
|
argument matches dummy_function
|
||||||
eval(1) = 2
|
eval(1) = 2
|
||||||
roundtrip..
|
roundtrip..
|
||||||
@ -36,6 +39,7 @@ could not convert to a function pointer.
|
|||||||
All OK!
|
All OK!
|
||||||
could not convert to a function pointer.
|
could not convert to a function pointer.
|
||||||
All OK!
|
All OK!
|
||||||
|
|
||||||
test_callback3(arg0: Callable[[int], int]) -> None
|
test_callback3(arg0: Callable[[int], int]) -> None
|
||||||
|
|
||||||
test_callback4() -> Callable[[int], int]
|
test_callback4() -> Callable[[int], int]
|
||||||
|
|
||||||
|
@ -8,32 +8,25 @@
|
|||||||
BSD-style license that can be found in the LICENSE file.
|
BSD-style license that can be found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <list>
|
||||||
#include "example.h"
|
#include "example.h"
|
||||||
|
#include "constructor-stats.h"
|
||||||
|
|
||||||
class ExampleMandA {
|
class ExampleMandA {
|
||||||
public:
|
public:
|
||||||
ExampleMandA() {
|
ExampleMandA() { print_default_created(this); }
|
||||||
cout << "Called ExampleMandA default constructor.." << endl;
|
ExampleMandA(int value) : value(value) { print_created(this, value); }
|
||||||
}
|
ExampleMandA(const ExampleMandA &e) : value(e.value) { print_copy_created(this); }
|
||||||
ExampleMandA(int value) : value(value) {
|
ExampleMandA(ExampleMandA &&e) : value(e.value) { print_move_created(this); }
|
||||||
cout << "Called ExampleMandA constructor with value " << value << ".." << endl;
|
~ExampleMandA() { print_destroyed(this); }
|
||||||
}
|
|
||||||
ExampleMandA(const ExampleMandA &e) : value(e.value) {
|
|
||||||
cout << "Called ExampleMandA copy constructor with value " << value << ".." << endl;
|
|
||||||
}
|
|
||||||
ExampleMandA(ExampleMandA &&e) : value(e.value) {
|
|
||||||
cout << "Called ExampleMandA move constructor with value " << value << ".." << endl;
|
|
||||||
e.value = 0;
|
|
||||||
}
|
|
||||||
~ExampleMandA() {
|
|
||||||
cout << "Called ExampleMandA destructor (" << value << ")" << endl;
|
|
||||||
}
|
|
||||||
std::string toString() {
|
std::string toString() {
|
||||||
return "ExampleMandA[value=" + std::to_string(value) + "]";
|
return "ExampleMandA[value=" + std::to_string(value) + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator=(const ExampleMandA &e) { cout << "Assignment operator" << endl; value = e.value; }
|
void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; }
|
||||||
void operator=(ExampleMandA &&e) { cout << "Move assignment operator" << endl; value = e.value; e.value = 0;}
|
void operator=(ExampleMandA &&e) { print_move_assigned(this); value = e.value; }
|
||||||
|
|
||||||
void add1(ExampleMandA other) { value += other.value; } // passing by value
|
void add1(ExampleMandA other) { value += other.value; } // passing by value
|
||||||
void add2(ExampleMandA &other) { value += other.value; } // passing by reference
|
void add2(ExampleMandA &other) { value += other.value; } // passing by reference
|
||||||
@ -88,5 +81,6 @@ void init_ex_methods_and_attributes(py::module &m) {
|
|||||||
.def("internal4", &ExampleMandA::internal4)
|
.def("internal4", &ExampleMandA::internal4)
|
||||||
.def("internal5", &ExampleMandA::internal5)
|
.def("internal5", &ExampleMandA::internal5)
|
||||||
.def("__str__", &ExampleMandA::toString)
|
.def("__str__", &ExampleMandA::toString)
|
||||||
.def_readwrite("value", &ExampleMandA::value);
|
.def_readwrite("value", &ExampleMandA::value)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
@ -35,3 +35,16 @@ print(instance1.internal5())
|
|||||||
print("Instance 1, direct access = %i" % instance1.value)
|
print("Instance 1, direct access = %i" % instance1.value)
|
||||||
instance1.value = 100
|
instance1.value = 100
|
||||||
print("Instance 1: " + str(instance1))
|
print("Instance 1: " + str(instance1))
|
||||||
|
|
||||||
|
from example import ConstructorStats
|
||||||
|
|
||||||
|
cstats = ConstructorStats.get(ExampleMandA)
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
instance1 = instance2 = None
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
print("Constructor values:", cstats.values())
|
||||||
|
print("Default constructions:", cstats.default_constructions)
|
||||||
|
print("Copy constructions:", cstats.copy_constructions)
|
||||||
|
print("Move constructions:", cstats.move_constructions >= 1)
|
||||||
|
print("Copy assignments:", cstats.copy_assignments)
|
||||||
|
print("Move assignments:", cstats.move_assignments)
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
Called ExampleMandA default constructor..
|
### ExampleMandA @ 0x2801910 created via default constructor
|
||||||
Called ExampleMandA constructor with value 32..
|
### ExampleMandA @ 0x27fa780 created 32
|
||||||
Called ExampleMandA copy constructor with value 32..
|
### ExampleMandA @ 0x7fff80a98a74 created via copy constructor
|
||||||
Called ExampleMandA copy constructor with value 32..
|
### ExampleMandA @ 0x7fff80a98a78 created via copy constructor
|
||||||
Called ExampleMandA destructor (32)
|
### ExampleMandA @ 0x7fff80a98a78 destroyed
|
||||||
Called ExampleMandA destructor (32)
|
### ExampleMandA @ 0x7fff80a98a74 destroyed
|
||||||
Instance 1: ExampleMandA[value=320]
|
Instance 1: ExampleMandA[value=320]
|
||||||
Instance 2: ExampleMandA[value=32]
|
Instance 2: ExampleMandA[value=32]
|
||||||
Called ExampleMandA copy constructor with value 320..
|
### ExampleMandA @ 0x7fff80a98a84 created via copy constructor
|
||||||
Called ExampleMandA move constructor with value 320..
|
### ExampleMandA @ 0x2801fd0 created via move constructor
|
||||||
Called ExampleMandA destructor (0)
|
### ExampleMandA @ 0x7fff80a98a84 destroyed
|
||||||
ExampleMandA[value=320]
|
ExampleMandA[value=320]
|
||||||
Called ExampleMandA destructor (320)
|
### ExampleMandA @ 0x2801fd0 destroyed
|
||||||
ExampleMandA[value=320]
|
ExampleMandA[value=320]
|
||||||
ExampleMandA[value=320]
|
ExampleMandA[value=320]
|
||||||
ExampleMandA[value=320]
|
ExampleMandA[value=320]
|
||||||
@ -22,5 +22,13 @@ ExampleMandA[value=320]
|
|||||||
320
|
320
|
||||||
Instance 1, direct access = 320
|
Instance 1, direct access = 320
|
||||||
Instance 1: ExampleMandA[value=100]
|
Instance 1: ExampleMandA[value=100]
|
||||||
Called ExampleMandA destructor (32)
|
Instances not destroyed: 2
|
||||||
Called ExampleMandA destructor (100)
|
### ExampleMandA @ 0x2801910 destroyed
|
||||||
|
### ExampleMandA @ 0x27fa780 destroyed
|
||||||
|
Instances not destroyed: 0
|
||||||
|
Constructor values: ['32']
|
||||||
|
Default constructions: 1
|
||||||
|
Copy constructions: 3
|
||||||
|
Move constructions: True
|
||||||
|
Copy assignments: 0
|
||||||
|
Move assignments: 0
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "example.h"
|
#include "example.h"
|
||||||
|
#include "constructor-stats.h"
|
||||||
|
|
||||||
void submodule_func() {
|
void submodule_func() {
|
||||||
std::cout << "submodule_func()" << std::endl;
|
std::cout << "submodule_func()" << std::endl;
|
||||||
@ -16,9 +17,10 @@ void submodule_func() {
|
|||||||
|
|
||||||
class A {
|
class A {
|
||||||
public:
|
public:
|
||||||
A(int v) : v(v) { std::cout << "A constructor" << std::endl; }
|
A(int v) : v(v) { print_created(this, v); }
|
||||||
~A() { std::cout << "A destructor" << std::endl; }
|
~A() { print_destroyed(this); }
|
||||||
A(const A&) { std::cout << "A copy constructor" << std::endl; }
|
A(const A&) { print_copy_created(this); }
|
||||||
|
A& operator=(const A ©) { print_copy_assigned(this); v = copy.v; return *this; }
|
||||||
std::string toString() { return "A[" + std::to_string(v) + "]"; }
|
std::string toString() { return "A[" + std::to_string(v) + "]"; }
|
||||||
private:
|
private:
|
||||||
int v;
|
int v;
|
||||||
@ -26,9 +28,10 @@ private:
|
|||||||
|
|
||||||
class B {
|
class B {
|
||||||
public:
|
public:
|
||||||
B() { std::cout << "B constructor" << std::endl; }
|
B() { print_default_created(this); }
|
||||||
~B() { std::cout << "B destructor" << std::endl; }
|
~B() { print_destroyed(this); }
|
||||||
B(const B&) { std::cout << "B copy constructor" << std::endl; }
|
B(const B&) { print_copy_created(this); }
|
||||||
|
B& operator=(const B ©) { print_copy_assigned(this); a1 = copy.a1; a2 = copy.a2; return *this; }
|
||||||
A &get_a1() { return a1; }
|
A &get_a1() { return a1; }
|
||||||
A &get_a2() { return a2; }
|
A &get_a2() { return a2; }
|
||||||
|
|
||||||
|
@ -28,3 +28,16 @@ print(b.get_a2())
|
|||||||
print(b.a2)
|
print(b.a2)
|
||||||
|
|
||||||
print(OD([(1, 'a'), (2, 'b')]))
|
print(OD([(1, 'a'), (2, 'b')]))
|
||||||
|
|
||||||
|
from example import ConstructorStats
|
||||||
|
|
||||||
|
cstats = [ConstructorStats.get(A), ConstructorStats.get(B)]
|
||||||
|
print("Instances not destroyed:", [x.alive() for x in cstats])
|
||||||
|
b = None
|
||||||
|
print("Instances not destroyed:", [x.alive() for x in cstats])
|
||||||
|
print("Constructor values:", [x.values() for x in cstats])
|
||||||
|
print("Default constructions:", [x.default_constructions for x in cstats])
|
||||||
|
print("Copy constructions:", [x.copy_constructions for x in cstats])
|
||||||
|
#print("Move constructions:", [x.move_constructions >= 0 for x in cstats]) # Don't invoke any
|
||||||
|
print("Copy assignments:", [x.copy_assignments for x in cstats])
|
||||||
|
print("Move assignments:", [x.move_assignments for x in cstats])
|
||||||
|
@ -1,22 +1,31 @@
|
|||||||
example
|
example
|
||||||
example.submodule
|
example.submodule
|
||||||
submodule_func()
|
submodule_func()
|
||||||
A constructor
|
### A @ 0x21a5bc0 created 1
|
||||||
A constructor
|
### A @ 0x21a5bc4 created 2
|
||||||
B constructor
|
### B @ 0x21a5bc0 created via default constructor
|
||||||
A[1]
|
A[1]
|
||||||
A[1]
|
A[1]
|
||||||
A[2]
|
A[2]
|
||||||
A[2]
|
A[2]
|
||||||
A constructor
|
### A @ 0x20f93b0 created 42
|
||||||
A destructor
|
### A @ 0x21a5bc0 assigned via copy assignment
|
||||||
A constructor
|
### A @ 0x20f93b0 destroyed
|
||||||
A destructor
|
### A @ 0x20f93d0 created 43
|
||||||
|
### A @ 0x21a5bc4 assigned via copy assignment
|
||||||
|
### A @ 0x20f93d0 destroyed
|
||||||
A[42]
|
A[42]
|
||||||
A[42]
|
A[42]
|
||||||
A[43]
|
A[43]
|
||||||
A[43]
|
A[43]
|
||||||
OrderedDict([(1, 'a'), (2, 'b')])
|
OrderedDict([(1, 'a'), (2, 'b')])
|
||||||
B destructor
|
Instances not destroyed: [2, 1]
|
||||||
A destructor
|
### B @ 0x21a5bc0 destroyed
|
||||||
A destructor
|
### A @ 0x21a5bc4 destroyed
|
||||||
|
### A @ 0x21a5bc0 destroyed
|
||||||
|
Instances not destroyed: [0, 0]
|
||||||
|
Constructor values: [['1', '2', '42', '43'], []]
|
||||||
|
Default constructions: [0, 1]
|
||||||
|
Copy constructions: [0, 0]
|
||||||
|
Copy assignments: [2, 0]
|
||||||
|
Move assignments: [0, 0]
|
||||||
|
@ -34,6 +34,8 @@ print_opaque_list(cvp.stringList)
|
|||||||
|
|
||||||
print_void_ptr(return_void_ptr())
|
print_void_ptr(return_void_ptr())
|
||||||
print_void_ptr(ExampleMandA()) # Should also work for other C++ types
|
print_void_ptr(ExampleMandA()) # Should also work for other C++ types
|
||||||
|
from example import ConstructorStats
|
||||||
|
print("ExampleMandA still alive:", ConstructorStats.get(ExampleMandA).alive())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print_void_ptr([1, 2, 3]) # This should not work
|
print_void_ptr([1, 2, 3]) # This should not work
|
||||||
|
@ -6,13 +6,14 @@ Opaque list: [Element 1]
|
|||||||
Opaque list: []
|
Opaque list: []
|
||||||
Opaque list: [Element 1, Element 3]
|
Opaque list: [Element 1, Element 3]
|
||||||
Got void ptr : 0x1234
|
Got void ptr : 0x1234
|
||||||
Called ExampleMandA default constructor..
|
### ExampleMandA @ 0x2ac5370 created via default constructor
|
||||||
Got void ptr : 0x7f9ba0f3c430
|
Got void ptr : 0x2ac5370
|
||||||
Called ExampleMandA destructor (0)
|
### ExampleMandA @ 0x2ac5370 destroyed
|
||||||
|
ExampleMandA still alive: 0
|
||||||
Caught expected exception: Incompatible function arguments. The following argument types are supported:
|
Caught expected exception: Incompatible function arguments. The following argument types are supported:
|
||||||
1. (arg0: capsule) -> None
|
1. (arg0: capsule) -> None
|
||||||
Invoked with: [1, 2, 3]
|
Invoked with: [1, 2, 3]
|
||||||
None
|
None
|
||||||
Got null str : 0x0
|
Got null str : 0x0
|
||||||
<example.StringList object at 0x10d3277a0>
|
<example.StringList object at 0x7f7ecde6fc00>
|
||||||
Opaque list: [some value]
|
Opaque list: [some value]
|
||||||
|
@ -8,27 +8,28 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "example.h"
|
#include "example.h"
|
||||||
|
#include "constructor-stats.h"
|
||||||
#include <pybind11/operators.h>
|
#include <pybind11/operators.h>
|
||||||
|
|
||||||
class Vector2 {
|
class Vector2 {
|
||||||
public:
|
public:
|
||||||
Vector2(float x, float y) : x(x), y(y) { std::cout << "Value constructor" << std::endl; }
|
Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); }
|
||||||
Vector2(const Vector2 &v) : x(v.x), y(v.y) { std::cout << "Copy constructor" << std::endl; }
|
Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); }
|
||||||
Vector2(Vector2 &&v) : x(v.x), y(v.y) { std::cout << "Move constructor" << std::endl; v.x = v.y = 0; }
|
Vector2(Vector2 &&v) : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; }
|
||||||
~Vector2() { std::cout << "Destructor." << std::endl; }
|
~Vector2() { print_destroyed(this); }
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
return "[" + std::to_string(x) + ", " + std::to_string(y) + "]";
|
return "[" + std::to_string(x) + ", " + std::to_string(y) + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator=(const Vector2 &v) {
|
void operator=(const Vector2 &v) {
|
||||||
cout << "Assignment operator" << endl;
|
print_copy_assigned(this);
|
||||||
x = v.x;
|
x = v.x;
|
||||||
y = v.y;
|
y = v.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator=(Vector2 &&v) {
|
void operator=(Vector2 &&v) {
|
||||||
cout << "Move assignment operator" << endl;
|
print_move_assigned(this);
|
||||||
x = v.x; y = v.y; v.x = v.y = 0;
|
x = v.x; y = v.y; v.x = v.y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +52,6 @@ private:
|
|||||||
float x, y;
|
float x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void init_ex_operator_overloading(py::module &m) {
|
void init_ex_operator_overloading(py::module &m) {
|
||||||
py::class_<Vector2>(m, "Vector2")
|
py::class_<Vector2>(m, "Vector2")
|
||||||
.def(py::init<float, float>())
|
.def(py::init<float, float>())
|
||||||
@ -69,7 +69,8 @@ void init_ex_operator_overloading(py::module &m) {
|
|||||||
.def(float() - py::self)
|
.def(float() - py::self)
|
||||||
.def(float() * py::self)
|
.def(float() * py::self)
|
||||||
.def(float() / py::self)
|
.def(float() / py::self)
|
||||||
.def("__str__", &Vector2::toString);
|
.def("__str__", &Vector2::toString)
|
||||||
|
;
|
||||||
|
|
||||||
m.attr("Vector") = m.attr("Vector2");
|
m.attr("Vector") = m.attr("Vector2");
|
||||||
}
|
}
|
||||||
|
@ -25,3 +25,17 @@ v1 += v2
|
|||||||
v1 *= 2
|
v1 *= 2
|
||||||
|
|
||||||
print("(v1+v2)*2 = " + str(v1))
|
print("(v1+v2)*2 = " + str(v1))
|
||||||
|
|
||||||
|
from example import ConstructorStats
|
||||||
|
cstats = ConstructorStats.get(Vector2)
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
v1 = None
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
v2 = None
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
print("Constructor values:", cstats.values())
|
||||||
|
print("Default constructions:", cstats.default_constructions)
|
||||||
|
print("Copy constructions:", cstats.copy_constructions)
|
||||||
|
print("Move constructions:", cstats.move_constructions >= 10)
|
||||||
|
print("Copy assignments:", cstats.copy_assignments)
|
||||||
|
print("Move assignments:", cstats.move_assignments)
|
||||||
|
@ -1,57 +1,66 @@
|
|||||||
Value constructor
|
### Vector2 @ 0x11f7830 created [1.000000, 2.000000]
|
||||||
Value constructor
|
### Vector2 @ 0x11427c0 created [3.000000, -1.000000]
|
||||||
v1 = [1.000000, 2.000000]
|
v1 = [1.000000, 2.000000]
|
||||||
v2 = [3.000000, -1.000000]
|
v2 = [3.000000, -1.000000]
|
||||||
Value constructor
|
### Vector2 @ 0x7ffef6b144b8 created [4.000000, 1.000000]
|
||||||
Move constructor
|
### Vector2 @ 0x11f7e90 created via move constructor
|
||||||
Destructor.
|
### Vector2 @ 0x7ffef6b144b8 destroyed
|
||||||
Destructor.
|
### Vector2 @ 0x11f7e90 destroyed
|
||||||
v1+v2 = [4.000000, 1.000000]
|
v1+v2 = [4.000000, 1.000000]
|
||||||
Value constructor
|
### Vector2 @ 0x7ffef6b144b8 created [-2.000000, 3.000000]
|
||||||
Move constructor
|
### Vector2 @ 0x11f7e90 created via move constructor
|
||||||
Destructor.
|
### Vector2 @ 0x7ffef6b144b8 destroyed
|
||||||
Destructor.
|
### Vector2 @ 0x11f7e90 destroyed
|
||||||
v1-v2 = [-2.000000, 3.000000]
|
v1-v2 = [-2.000000, 3.000000]
|
||||||
Value constructor
|
### Vector2 @ 0x7ffef6b144c8 created [-7.000000, -6.000000]
|
||||||
Move constructor
|
### Vector2 @ 0x1115760 created via move constructor
|
||||||
Destructor.
|
### Vector2 @ 0x7ffef6b144c8 destroyed
|
||||||
Destructor.
|
### Vector2 @ 0x1115760 destroyed
|
||||||
v1-8 = [-7.000000, -6.000000]
|
v1-8 = [-7.000000, -6.000000]
|
||||||
Value constructor
|
### Vector2 @ 0x7ffef6b144c8 created [9.000000, 10.000000]
|
||||||
Move constructor
|
### Vector2 @ 0x1115760 created via move constructor
|
||||||
Destructor.
|
### Vector2 @ 0x7ffef6b144c8 destroyed
|
||||||
Destructor.
|
### Vector2 @ 0x1115760 destroyed
|
||||||
v1+8 = [9.000000, 10.000000]
|
v1+8 = [9.000000, 10.000000]
|
||||||
Value constructor
|
### Vector2 @ 0x7ffef6b144b8 created [8.000000, 16.000000]
|
||||||
Move constructor
|
### Vector2 @ 0x1115760 created via move constructor
|
||||||
Destructor.
|
### Vector2 @ 0x7ffef6b144b8 destroyed
|
||||||
Destructor.
|
### Vector2 @ 0x1115760 destroyed
|
||||||
v1*8 = [8.000000, 16.000000]
|
v1*8 = [8.000000, 16.000000]
|
||||||
Value constructor
|
### Vector2 @ 0x7ffef6b144a8 created [0.125000, 0.250000]
|
||||||
Move constructor
|
### Vector2 @ 0x112f150 created via move constructor
|
||||||
Destructor.
|
### Vector2 @ 0x7ffef6b144a8 destroyed
|
||||||
Destructor.
|
### Vector2 @ 0x112f150 destroyed
|
||||||
v1/8 = [0.125000, 0.250000]
|
v1/8 = [0.125000, 0.250000]
|
||||||
Value constructor
|
### Vector2 @ 0x7ffef6b144f8 created [7.000000, 6.000000]
|
||||||
Move constructor
|
### Vector2 @ 0x112f1b0 created via move constructor
|
||||||
Destructor.
|
### Vector2 @ 0x7ffef6b144f8 destroyed
|
||||||
Destructor.
|
### Vector2 @ 0x112f1b0 destroyed
|
||||||
8-v1 = [7.000000, 6.000000]
|
8-v1 = [7.000000, 6.000000]
|
||||||
Value constructor
|
### Vector2 @ 0x7ffef6b144f8 created [9.000000, 10.000000]
|
||||||
Move constructor
|
### Vector2 @ 0x112f1b0 created via move constructor
|
||||||
Destructor.
|
### Vector2 @ 0x7ffef6b144f8 destroyed
|
||||||
Destructor.
|
### Vector2 @ 0x112f1b0 destroyed
|
||||||
8+v1 = [9.000000, 10.000000]
|
8+v1 = [9.000000, 10.000000]
|
||||||
Value constructor
|
### Vector2 @ 0x7ffef6b144e8 created [8.000000, 16.000000]
|
||||||
Move constructor
|
### Vector2 @ 0x112f230 created via move constructor
|
||||||
Destructor.
|
### Vector2 @ 0x7ffef6b144e8 destroyed
|
||||||
Destructor.
|
### Vector2 @ 0x112f230 destroyed
|
||||||
8*v1 = [8.000000, 16.000000]
|
8*v1 = [8.000000, 16.000000]
|
||||||
Value constructor
|
### Vector2 @ 0x7ffef6b144d8 created [8.000000, 4.000000]
|
||||||
Move constructor
|
### Vector2 @ 0x11fb360 created via move constructor
|
||||||
Destructor.
|
### Vector2 @ 0x7ffef6b144d8 destroyed
|
||||||
Destructor.
|
### Vector2 @ 0x11fb360 destroyed
|
||||||
8/v1 = [8.000000, 4.000000]
|
8/v1 = [8.000000, 4.000000]
|
||||||
(v1+v2)*2 = [8.000000, 2.000000]
|
(v1+v2)*2 = [8.000000, 2.000000]
|
||||||
Destructor.
|
Instances not destroyed: 2
|
||||||
Destructor.
|
### Vector2 @ 0x11f7830 destroyed
|
||||||
|
Instances not destroyed: 1
|
||||||
|
### Vector2 @ 0x11427c0 destroyed
|
||||||
|
Instances not destroyed: 0
|
||||||
|
Constructor values: ['[1.000000, 2.000000]', '[3.000000, -1.000000]', '[4.000000, 1.000000]', '[-2.000000, 3.000000]', '[-7.000000, -6.000000]', '[9.000000, 10.000000]', '[8.000000, 16.000000]', '[0.125000, 0.250000]', '[7.000000, 6.000000]', '[9.000000, 10.000000]', '[8.000000, 16.000000]', '[8.000000, 4.000000]']
|
||||||
|
Default constructions: 0
|
||||||
|
Copy constructions: 0
|
||||||
|
Move constructions: True
|
||||||
|
Copy assignments: 0
|
||||||
|
Move assignments: 0
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "example.h"
|
#include "example.h"
|
||||||
|
#include "constructor-stats.h"
|
||||||
#include <pybind11/stl.h>
|
#include <pybind11/stl.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -19,11 +20,11 @@
|
|||||||
class ExamplePythonTypes {
|
class ExamplePythonTypes {
|
||||||
public:
|
public:
|
||||||
static ExamplePythonTypes *new_instance() {
|
static ExamplePythonTypes *new_instance() {
|
||||||
return new ExamplePythonTypes();
|
auto *ptr = new ExamplePythonTypes();
|
||||||
}
|
print_created(ptr, "via new_instance");
|
||||||
~ExamplePythonTypes() {
|
return ptr;
|
||||||
std::cout << "Destructing ExamplePythonTypes" << std::endl;
|
|
||||||
}
|
}
|
||||||
|
~ExamplePythonTypes() { print_destroyed(this); }
|
||||||
|
|
||||||
/* Create and return a Python dictionary */
|
/* Create and return a Python dictionary */
|
||||||
py::dict get_dict() {
|
py::dict get_dict() {
|
||||||
@ -168,5 +169,6 @@ void init_ex_python_types(py::module &m) {
|
|||||||
.def("throw_exception", &ExamplePythonTypes::throw_exception, "Throw an exception")
|
.def("throw_exception", &ExamplePythonTypes::throw_exception, "Throw an exception")
|
||||||
.def_static("new_instance", &ExamplePythonTypes::new_instance, "Return an instance")
|
.def_static("new_instance", &ExamplePythonTypes::new_instance, "Return an instance")
|
||||||
.def_readwrite_static("value", &ExamplePythonTypes::value, "Static value member")
|
.def_readwrite_static("value", &ExamplePythonTypes::value, "Static value member")
|
||||||
.def_readonly_static("value2", &ExamplePythonTypes::value2, "Static value member (readonly)");
|
.def_readonly_static("value2", &ExamplePythonTypes::value2, "Static value member (readonly)")
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
@ -65,3 +65,10 @@ print("__name__(example.ExamplePythonTypes) = %s" % ExamplePythonTypes.__name__)
|
|||||||
print("__module__(example.ExamplePythonTypes) = %s" % ExamplePythonTypes.__module__)
|
print("__module__(example.ExamplePythonTypes) = %s" % ExamplePythonTypes.__module__)
|
||||||
print("__name__(example.ExamplePythonTypes.get_set) = %s" % ExamplePythonTypes.get_set.__name__)
|
print("__name__(example.ExamplePythonTypes.get_set) = %s" % ExamplePythonTypes.get_set.__name__)
|
||||||
print("__module__(example.ExamplePythonTypes.get_set) = %s" % ExamplePythonTypes.get_set.__module__)
|
print("__module__(example.ExamplePythonTypes.get_set) = %s" % ExamplePythonTypes.get_set.__module__)
|
||||||
|
|
||||||
|
from example import ConstructorStats
|
||||||
|
|
||||||
|
cstats = ConstructorStats.get(ExamplePythonTypes)
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
instance = None
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
5
|
5
|
||||||
example.ExamplePythonTypes: No constructor defined!
|
example.ExamplePythonTypes: No constructor defined!
|
||||||
can't set attribute
|
can't set attribute
|
||||||
|
### ExamplePythonTypes @ 0x1045b80 created via new_instance
|
||||||
key: key2, value=value2
|
key: key2, value=value2
|
||||||
key: key, value=value
|
key: key, value=value
|
||||||
key: key, value=value
|
key: key, value=value
|
||||||
@ -134,4 +135,6 @@ __name__(example.ExamplePythonTypes) = ExamplePythonTypes
|
|||||||
__module__(example.ExamplePythonTypes) = example
|
__module__(example.ExamplePythonTypes) = example
|
||||||
__name__(example.ExamplePythonTypes.get_set) = get_set
|
__name__(example.ExamplePythonTypes.get_set) = get_set
|
||||||
__module__(example.ExamplePythonTypes.get_set) = example
|
__module__(example.ExamplePythonTypes.get_set) = example
|
||||||
Destructing ExamplePythonTypes
|
Instances not destroyed: 1
|
||||||
|
### ExamplePythonTypes @ 0x1045b80 destroyed
|
||||||
|
Instances not destroyed: 0
|
||||||
|
@ -9,51 +9,55 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "example.h"
|
#include "example.h"
|
||||||
|
#include "constructor-stats.h"
|
||||||
#include <pybind11/operators.h>
|
#include <pybind11/operators.h>
|
||||||
#include <pybind11/stl.h>
|
#include <pybind11/stl.h>
|
||||||
|
|
||||||
class Sequence {
|
class Sequence {
|
||||||
public:
|
public:
|
||||||
Sequence(size_t size) : m_size(size) {
|
Sequence(size_t size) : m_size(size) {
|
||||||
std::cout << "Value constructor: Creating a sequence with " << m_size << " entries" << std::endl;
|
print_created(this, "of size", m_size);
|
||||||
m_data = new float[size];
|
m_data = new float[size];
|
||||||
memset(m_data, 0, sizeof(float) * size);
|
memset(m_data, 0, sizeof(float) * size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequence(const std::vector<float> &value) : m_size(value.size()) {
|
Sequence(const std::vector<float> &value) : m_size(value.size()) {
|
||||||
std::cout << "Value constructor: Creating a sequence with " << m_size << " entries" << std::endl;
|
print_created(this, "of size", m_size, "from std::vector");
|
||||||
m_data = new float[m_size];
|
m_data = new float[m_size];
|
||||||
memcpy(m_data, &value[0], sizeof(float) * m_size);
|
memcpy(m_data, &value[0], sizeof(float) * m_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequence(const Sequence &s) : m_size(s.m_size) {
|
Sequence(const Sequence &s) : m_size(s.m_size) {
|
||||||
std::cout << "Copy constructor: Creating a sequence with " << m_size << " entries" << std::endl;
|
print_copy_created(this);
|
||||||
m_data = new float[m_size];
|
m_data = new float[m_size];
|
||||||
memcpy(m_data, s.m_data, sizeof(float)*m_size);
|
memcpy(m_data, s.m_data, sizeof(float)*m_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequence(Sequence &&s) : m_size(s.m_size), m_data(s.m_data) {
|
Sequence(Sequence &&s) : m_size(s.m_size), m_data(s.m_data) {
|
||||||
std::cout << "Move constructor: Creating a sequence with " << m_size << " entries" << std::endl;
|
print_move_created(this);
|
||||||
s.m_size = 0;
|
s.m_size = 0;
|
||||||
s.m_data = nullptr;
|
s.m_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
~Sequence() {
|
~Sequence() {
|
||||||
std::cout << "Freeing a sequence with " << m_size << " entries" << std::endl;
|
print_destroyed(this);
|
||||||
delete[] m_data;
|
delete[] m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequence &operator=(const Sequence &s) {
|
Sequence &operator=(const Sequence &s) {
|
||||||
std::cout << "Assignment operator: Creating a sequence with " << s.m_size << " entries" << std::endl;
|
if (&s != this) {
|
||||||
delete[] m_data;
|
delete[] m_data;
|
||||||
m_size = s.m_size;
|
m_size = s.m_size;
|
||||||
m_data = new float[m_size];
|
m_data = new float[m_size];
|
||||||
memcpy(m_data, s.m_data, sizeof(float)*m_size);
|
memcpy(m_data, s.m_data, sizeof(float)*m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
print_copy_assigned(this);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequence &operator=(Sequence &&s) {
|
Sequence &operator=(Sequence &&s) {
|
||||||
std::cout << "Move assignment operator: Creating a sequence with " << s.m_size << " entries" << std::endl;
|
|
||||||
if (&s != this) {
|
if (&s != this) {
|
||||||
delete[] m_data;
|
delete[] m_data;
|
||||||
m_size = s.m_size;
|
m_size = s.m_size;
|
||||||
@ -61,6 +65,9 @@ public:
|
|||||||
s.m_size = 0;
|
s.m_size = 0;
|
||||||
s.m_data = nullptr;
|
s.m_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_move_assigned(this);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,3 +28,19 @@ rev[0::2] = Sequence([2.0, 2.0, 2.0])
|
|||||||
for i in rev:
|
for i in rev:
|
||||||
print(i, end=' ')
|
print(i, end=' ')
|
||||||
print('')
|
print('')
|
||||||
|
|
||||||
|
from example import ConstructorStats
|
||||||
|
cstats = ConstructorStats.get(Sequence)
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
s = None
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
rev = None
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
rev2 = None
|
||||||
|
print("Instances not destroyed:", cstats.alive())
|
||||||
|
print("Constructor values:", cstats.values())
|
||||||
|
print("Default constructions:", cstats.default_constructions)
|
||||||
|
print("Copy constructions:", cstats.copy_constructions)
|
||||||
|
print("Move constructions:", cstats.move_constructions >= 1)
|
||||||
|
print("Copy assignments:", cstats.copy_assignments)
|
||||||
|
print("Move assignments:", cstats.move_assignments)
|
||||||
|
@ -1,21 +1,31 @@
|
|||||||
Value constructor: Creating a sequence with 5 entries
|
### Sequence @ 0x1535b00 created of size 5
|
||||||
s = <example.Sequence object at 0x10c786c70>
|
s = <example.Sequence object at 0x7efc73cfa4e0>
|
||||||
len(s) = 5
|
len(s) = 5
|
||||||
s[0], s[3] = 0.000000 0.000000
|
s[0], s[3] = 0.000000 0.000000
|
||||||
12.34 in s: False
|
12.34 in s: False
|
||||||
12.34 in s: True
|
12.34 in s: True
|
||||||
s[0], s[3] = 12.340000 56.779999
|
s[0], s[3] = 12.340000 56.779999
|
||||||
Value constructor: Creating a sequence with 5 entries
|
### Sequence @ 0x7fff22a45068 created of size 5
|
||||||
Move constructor: Creating a sequence with 5 entries
|
### Sequence @ 0x1538b90 created via move constructor
|
||||||
Freeing a sequence with 0 entries
|
### Sequence @ 0x7fff22a45068 destroyed
|
||||||
Value constructor: Creating a sequence with 5 entries
|
### Sequence @ 0x1538bf0 created of size 5
|
||||||
rev[0], rev[1], rev[2], rev[3], rev[4] = 0.000000 56.779999 0.000000 0.000000 12.340000
|
rev[0], rev[1], rev[2], rev[3], rev[4] = 0.000000 56.779999 0.000000 0.000000 12.340000
|
||||||
0.0 56.7799987793 0.0 0.0 12.3400001526
|
0.0 56.779998779296875 0.0 0.0 12.34000015258789
|
||||||
0.0 56.7799987793 0.0 0.0 12.3400001526
|
0.0 56.779998779296875 0.0 0.0 12.34000015258789
|
||||||
True
|
True
|
||||||
Value constructor: Creating a sequence with 3 entries
|
### Sequence @ 0x153c4b0 created of size 3 from std::vector
|
||||||
Freeing a sequence with 3 entries
|
### Sequence @ 0x153c4b0 destroyed
|
||||||
2.0 56.7799987793 2.0 0.0 2.0
|
2.0 56.779998779296875 2.0 0.0 2.0
|
||||||
Freeing a sequence with 5 entries
|
Instances not destroyed: 3
|
||||||
Freeing a sequence with 5 entries
|
### Sequence @ 0x1535b00 destroyed
|
||||||
Freeing a sequence with 5 entries
|
Instances not destroyed: 2
|
||||||
|
### Sequence @ 0x1538b90 destroyed
|
||||||
|
Instances not destroyed: 1
|
||||||
|
### Sequence @ 0x1538bf0 destroyed
|
||||||
|
Instances not destroyed: 0
|
||||||
|
Constructor values: ['of size', '5', 'of size', '5', 'of size', '5', 'of size', '3', 'from std::vector']
|
||||||
|
Default constructions: 0
|
||||||
|
Copy constructions: 0
|
||||||
|
Move constructions: True
|
||||||
|
Copy assignments: 0
|
||||||
|
Move assignments: 0
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
class MyObject1 : public Object {
|
class MyObject1 : public Object {
|
||||||
public:
|
public:
|
||||||
MyObject1(int value) : value(value) {
|
MyObject1(int value) : value(value) {
|
||||||
std::cout << toString() << " constructor" << std::endl;
|
print_created(this, toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
@ -24,7 +24,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~MyObject1() {
|
virtual ~MyObject1() {
|
||||||
std::cout << toString() << " destructor" << std::endl;
|
print_destroyed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -35,7 +35,7 @@ private:
|
|||||||
class MyObject2 {
|
class MyObject2 {
|
||||||
public:
|
public:
|
||||||
MyObject2(int value) : value(value) {
|
MyObject2(int value) : value(value) {
|
||||||
std::cout << toString() << " constructor" << std::endl;
|
print_created(this, toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
@ -43,7 +43,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual ~MyObject2() {
|
virtual ~MyObject2() {
|
||||||
std::cout << toString() << " destructor" << std::endl;
|
print_destroyed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -54,7 +54,7 @@ private:
|
|||||||
class MyObject3 : public std::enable_shared_from_this<MyObject3> {
|
class MyObject3 : public std::enable_shared_from_this<MyObject3> {
|
||||||
public:
|
public:
|
||||||
MyObject3(int value) : value(value) {
|
MyObject3(int value) : value(value) {
|
||||||
std::cout << toString() << " constructor" << std::endl;
|
print_created(this, toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
@ -62,7 +62,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual ~MyObject3() {
|
virtual ~MyObject3() {
|
||||||
std::cout << toString() << " destructor" << std::endl;
|
print_destroyed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -144,4 +144,7 @@ void init_ex_smart_ptr(py::module &m) {
|
|||||||
m.def("print_myobject3_4", &print_myobject3_4);
|
m.def("print_myobject3_4", &print_myobject3_4);
|
||||||
|
|
||||||
py::implicitly_convertible<py::int_, MyObject1>();
|
py::implicitly_convertible<py::int_, MyObject1>();
|
||||||
|
|
||||||
|
// Expose constructor stats for the ref type
|
||||||
|
m.def("cstats_ref", &ConstructorStats::get<ref_tag>);
|
||||||
}
|
}
|
||||||
|
@ -68,3 +68,18 @@ for o in [MyObject3(9), make_myobject3_1(), make_myobject3_2()]:
|
|||||||
print_myobject3_2(o)
|
print_myobject3_2(o)
|
||||||
print_myobject3_3(o)
|
print_myobject3_3(o)
|
||||||
print_myobject3_4(o)
|
print_myobject3_4(o)
|
||||||
|
|
||||||
|
from example import ConstructorStats, cstats_ref, Object
|
||||||
|
|
||||||
|
cstats = [ConstructorStats.get(Object), ConstructorStats.get(MyObject1),
|
||||||
|
ConstructorStats.get(MyObject2), ConstructorStats.get(MyObject3),
|
||||||
|
cstats_ref()]
|
||||||
|
print("Instances not destroyed:", [x.alive() for x in cstats])
|
||||||
|
o = None
|
||||||
|
print("Instances not destroyed:", [x.alive() for x in cstats])
|
||||||
|
print("Object value constructions:", [x.values() for x in cstats])
|
||||||
|
print("Default constructions:", [x.default_constructions for x in cstats])
|
||||||
|
print("Copy constructions:", [x.copy_constructions for x in cstats])
|
||||||
|
#print("Move constructions:", [x.move_constructions >= 0 for x in cstats]) # Doesn't invoke any
|
||||||
|
print("Copy assignments:", [x.copy_assignments for x in cstats])
|
||||||
|
print("Move assignments:", [x.move_assignments for x in cstats])
|
||||||
|
@ -1,243 +1,270 @@
|
|||||||
MyObject1[1] constructor
|
### Object @ 0xdeffd0 created via default constructor
|
||||||
Initialized ref from pointer 0x1347ba0
|
### MyObject1 @ 0xdeffd0 created MyObject1[1]
|
||||||
MyObject1[2] constructor
|
### ref<MyObject1> @ 0x7f6a2e03c4a8 created from pointer 0xdeffd0
|
||||||
Initialized ref from pointer 0x12b9270
|
### Object @ 0xe43f50 created via default constructor
|
||||||
Initialized ref from ref 0x12b9270
|
### MyObject1 @ 0xe43f50 created MyObject1[2]
|
||||||
Destructing ref 0x12b9270
|
### ref<Object> @ 0x7fff136845d0 created from pointer 0xe43f50
|
||||||
MyObject1[3] constructor
|
### ref<MyObject1> @ 0x7f6a2c32aad8 created via copy constructor with pointer 0xe43f50
|
||||||
Initialized ref from pointer 0x12a2a90
|
### ref<Object> @ 0x7fff136845d0 destroyed
|
||||||
MyObject1[1]
|
### Object @ 0xee8cf0 created via default constructor
|
||||||
Created empty ref
|
### MyObject1 @ 0xee8cf0 created MyObject1[3]
|
||||||
Assigning ref 0x1347ba0
|
### ref<MyObject1> @ 0x7f6a2c32ab08 created from pointer 0xee8cf0
|
||||||
Initialized ref from ref 0x1347ba0
|
|
||||||
MyObject1[1]
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1347ba0
|
|
||||||
MyObject1[1]
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1347ba0
|
|
||||||
MyObject1[1]
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
MyObject1[2]
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x12b9270
|
|
||||||
Initialized ref from ref 0x12b9270
|
|
||||||
MyObject1[2]
|
|
||||||
Destructing ref 0x12b9270
|
|
||||||
Destructing ref 0x12b9270
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x12b9270
|
|
||||||
MyObject1[2]
|
|
||||||
Destructing ref 0x12b9270
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x12b9270
|
|
||||||
MyObject1[2]
|
|
||||||
Destructing ref 0x12b9270
|
|
||||||
MyObject1[3]
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x12a2a90
|
|
||||||
Initialized ref from ref 0x12a2a90
|
|
||||||
MyObject1[3]
|
|
||||||
Destructing ref 0x12a2a90
|
|
||||||
Destructing ref 0x12a2a90
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x12a2a90
|
|
||||||
MyObject1[3]
|
|
||||||
Destructing ref 0x12a2a90
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x12a2a90
|
|
||||||
MyObject1[3]
|
|
||||||
Destructing ref 0x12a2a90
|
|
||||||
Destructing ref 0x12b9270
|
|
||||||
MyObject1[2] destructor
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
MyObject1[1] destructor
|
|
||||||
MyObject1[4] constructor
|
|
||||||
Initialized ref from pointer 0x1347ba0
|
|
||||||
MyObject1[5] constructor
|
|
||||||
Initialized ref from pointer 0x1299190
|
|
||||||
Initialized ref from ref 0x1299190
|
|
||||||
Destructing ref 0x1299190
|
|
||||||
MyObject1[6] constructor
|
|
||||||
Initialized ref from pointer 0x133e2f0
|
|
||||||
Destructing ref 0x12a2a90
|
|
||||||
MyObject1[3] destructor
|
|
||||||
MyObject1[4]
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1347ba0
|
|
||||||
Initialized ref from ref 0x1347ba0
|
|
||||||
MyObject1[4]
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1347ba0
|
|
||||||
MyObject1[4]
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1347ba0
|
|
||||||
MyObject1[4]
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
MyObject1[4]
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1347ba0
|
|
||||||
Initialized ref from ref 0x1347ba0
|
|
||||||
MyObject1[4]
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1347ba0
|
|
||||||
MyObject1[4]
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1347ba0
|
|
||||||
MyObject1[4]
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
MyObject1[5]
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1299190
|
|
||||||
Initialized ref from ref 0x1299190
|
|
||||||
MyObject1[5]
|
|
||||||
Destructing ref 0x1299190
|
|
||||||
Destructing ref 0x1299190
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1299190
|
|
||||||
MyObject1[5]
|
|
||||||
Destructing ref 0x1299190
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1299190
|
|
||||||
MyObject1[5]
|
|
||||||
Destructing ref 0x1299190
|
|
||||||
MyObject1[5]
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1299190
|
|
||||||
Initialized ref from ref 0x1299190
|
|
||||||
MyObject1[5]
|
|
||||||
Destructing ref 0x1299190
|
|
||||||
Destructing ref 0x1299190
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1299190
|
|
||||||
MyObject1[5]
|
|
||||||
Destructing ref 0x1299190
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x1299190
|
|
||||||
MyObject1[5]
|
|
||||||
Destructing ref 0x1299190
|
|
||||||
MyObject1[6]
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x133e2f0
|
|
||||||
Initialized ref from ref 0x133e2f0
|
|
||||||
MyObject1[6]
|
|
||||||
Destructing ref 0x133e2f0
|
|
||||||
Destructing ref 0x133e2f0
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x133e2f0
|
|
||||||
MyObject1[6]
|
|
||||||
Destructing ref 0x133e2f0
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x133e2f0
|
|
||||||
MyObject1[6]
|
|
||||||
Destructing ref 0x133e2f0
|
|
||||||
MyObject1[6]
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x133e2f0
|
|
||||||
Initialized ref from ref 0x133e2f0
|
|
||||||
MyObject1[6]
|
|
||||||
Destructing ref 0x133e2f0
|
|
||||||
Destructing ref 0x133e2f0
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x133e2f0
|
|
||||||
MyObject1[6]
|
|
||||||
Destructing ref 0x133e2f0
|
|
||||||
Created empty ref
|
|
||||||
Assigning ref 0x133e2f0
|
|
||||||
MyObject1[6]
|
|
||||||
Destructing ref 0x133e2f0
|
|
||||||
MyObject1[7] constructor
|
|
||||||
Initialized ref from pointer 0x133f3a0
|
|
||||||
MyObject1[7]
|
|
||||||
Destructing ref 0x133f3a0
|
|
||||||
MyObject1[7] destructor
|
|
||||||
Created empty ref
|
|
||||||
MyObject1[7] constructor
|
|
||||||
Initialized ref from pointer 0x12a2a90
|
|
||||||
Assigning ref 0x12a2a90
|
|
||||||
Initialized ref from ref 0x12a2a90
|
|
||||||
MyObject1[7]
|
|
||||||
Destructing ref 0x12a2a90
|
|
||||||
Destructing ref 0x12a2a90
|
|
||||||
Destructing ref 0x12a2a90
|
|
||||||
MyObject1[7] destructor
|
|
||||||
Created empty ref
|
|
||||||
MyObject1[7] constructor
|
|
||||||
Initialized ref from pointer 0x133f3a0
|
|
||||||
Assigning ref 0x133f3a0
|
|
||||||
MyObject1[7]
|
|
||||||
Destructing ref 0x133f3a0
|
|
||||||
Destructing ref 0x133f3a0
|
|
||||||
MyObject1[7] destructor
|
|
||||||
Created empty ref
|
|
||||||
MyObject1[7] constructor
|
|
||||||
Initialized ref from pointer 0x12a2a90
|
|
||||||
Assigning ref 0x12a2a90
|
|
||||||
MyObject1[7]
|
|
||||||
Destructing ref 0x12a2a90
|
|
||||||
Destructing ref 0x12a2a90
|
|
||||||
MyObject1[7] destructor
|
|
||||||
Destructing ref 0x133e2f0
|
|
||||||
MyObject1[6] destructor
|
|
||||||
Destructing ref 0x1299190
|
|
||||||
MyObject1[5] destructor
|
|
||||||
Destructing ref 0x1347ba0
|
|
||||||
MyObject1[4] destructor
|
|
||||||
MyObject2[8] constructor
|
|
||||||
MyObject2[6] constructor
|
|
||||||
MyObject2[7] constructor
|
|
||||||
MyObject2[8]
|
|
||||||
MyObject2[8]
|
|
||||||
MyObject2[8]
|
|
||||||
MyObject2[8]
|
|
||||||
MyObject2[6]
|
|
||||||
MyObject2[6]
|
|
||||||
MyObject2[6]
|
|
||||||
MyObject2[6]
|
|
||||||
MyObject2[7]
|
|
||||||
MyObject2[7]
|
|
||||||
MyObject2[7]
|
|
||||||
MyObject2[7]
|
|
||||||
MyObject2[6] destructor
|
|
||||||
MyObject2[8] destructor
|
|
||||||
MyObject3[9] constructor
|
|
||||||
MyObject3[8] constructor
|
|
||||||
MyObject3[9] constructor
|
|
||||||
MyObject2[7] destructor
|
|
||||||
MyObject3[9]
|
|
||||||
MyObject3[9]
|
|
||||||
MyObject3[9]
|
|
||||||
MyObject3[9]
|
|
||||||
MyObject3[8]
|
|
||||||
MyObject3[8]
|
|
||||||
MyObject3[8]
|
|
||||||
MyObject3[8]
|
|
||||||
MyObject3[9]
|
|
||||||
MyObject3[9]
|
|
||||||
MyObject3[9]
|
|
||||||
MyObject3[9]
|
|
||||||
MyObject3[8] destructor
|
|
||||||
MyObject3[9] destructor
|
|
||||||
Reference count = 1
|
Reference count = 1
|
||||||
|
MyObject1[1]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xdeffd0
|
||||||
|
### ref<Object> @ 0x7fff136845a8 created via copy constructor with pointer 0xdeffd0
|
||||||
|
MyObject1[1]
|
||||||
|
### ref<Object> @ 0x7fff136845a8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xdeffd0
|
||||||
|
MyObject1[1]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xdeffd0
|
||||||
|
MyObject1[1]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
Reference count = 1
|
Reference count = 1
|
||||||
|
MyObject1[2]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xe43f50
|
||||||
|
### ref<Object> @ 0x7fff136845a8 created via copy constructor with pointer 0xe43f50
|
||||||
|
MyObject1[2]
|
||||||
|
### ref<Object> @ 0x7fff136845a8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xe43f50
|
||||||
|
MyObject1[2]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xe43f50
|
||||||
|
MyObject1[2]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
Reference count = 1
|
Reference count = 1
|
||||||
<example.MyObject1 object at 0x7f830b500e68>
|
MyObject1[3]
|
||||||
<example.MyObject1 object at 0x7f830b4fc688>
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
<example.MyObject1 object at 0x7f830b4fc5a8>
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8cf0
|
||||||
|
### ref<Object> @ 0x7fff136845a8 created via copy constructor with pointer 0xee8cf0
|
||||||
|
MyObject1[3]
|
||||||
|
### ref<Object> @ 0x7fff136845a8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8cf0
|
||||||
|
MyObject1[3]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8cf0
|
||||||
|
MyObject1[3]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
### MyObject1 @ 0xe43f50 destroyed
|
||||||
|
### Object @ 0xe43f50 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7f6a2c32aad8 destroyed
|
||||||
|
### MyObject1 @ 0xdeffd0 destroyed
|
||||||
|
### Object @ 0xdeffd0 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7f6a2e03c4a8 destroyed
|
||||||
|
### Object @ 0xee8310 created via default constructor
|
||||||
|
### MyObject1 @ 0xee8310 created MyObject1[4]
|
||||||
|
### ref<MyObject1> @ 0x7f6a2e03c4a8 created from pointer 0xee8310
|
||||||
|
### Object @ 0xee8470 created via default constructor
|
||||||
|
### MyObject1 @ 0xee8470 created MyObject1[5]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845d0 created from pointer 0xee8470
|
||||||
|
### ref<MyObject1> @ 0x7f6a2c32aad8 created via copy constructor with pointer 0xee8470
|
||||||
|
### ref<MyObject1> @ 0x7fff136845d0 destroyed
|
||||||
|
### Object @ 0xee95a0 created via default constructor
|
||||||
|
### MyObject1 @ 0xee95a0 created MyObject1[6]
|
||||||
|
### ref<MyObject1> @ 0x7f6a2c32ab38 created from pointer 0xee95a0
|
||||||
|
### MyObject1 @ 0xee8cf0 destroyed
|
||||||
|
### Object @ 0xee8cf0 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7f6a2c32ab08 destroyed
|
||||||
|
<example.MyObject1 object at 0x7f6a2e03c480>
|
||||||
|
MyObject1[4]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310
|
||||||
|
### ref<Object> @ 0x7fff136845a8 created via copy constructor with pointer 0xee8310
|
||||||
|
MyObject1[4]
|
||||||
|
### ref<Object> @ 0x7fff136845a8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310
|
||||||
|
MyObject1[4]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310
|
||||||
|
MyObject1[4]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
MyObject1[4]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310
|
||||||
|
### ref<MyObject1> @ 0x7fff136845a8 created via copy constructor with pointer 0xee8310
|
||||||
|
MyObject1[4]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845a8 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310
|
||||||
|
MyObject1[4]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310
|
||||||
|
MyObject1[4]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 destroyed
|
||||||
|
<example.MyObject1 object at 0x7f6a2c32aab0>
|
||||||
|
MyObject1[5]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470
|
||||||
|
### ref<Object> @ 0x7fff136845a8 created via copy constructor with pointer 0xee8470
|
||||||
|
MyObject1[5]
|
||||||
|
### ref<Object> @ 0x7fff136845a8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470
|
||||||
|
MyObject1[5]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470
|
||||||
|
MyObject1[5]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
MyObject1[5]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470
|
||||||
|
### ref<MyObject1> @ 0x7fff136845a8 created via copy constructor with pointer 0xee8470
|
||||||
|
MyObject1[5]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845a8 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470
|
||||||
|
MyObject1[5]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470
|
||||||
|
MyObject1[5]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 destroyed
|
||||||
|
<example.MyObject1 object at 0x7f6a2c32ab10>
|
||||||
|
MyObject1[6]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0
|
||||||
|
### ref<Object> @ 0x7fff136845a8 created via copy constructor with pointer 0xee95a0
|
||||||
|
MyObject1[6]
|
||||||
|
### ref<Object> @ 0x7fff136845a8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0
|
||||||
|
MyObject1[6]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0
|
||||||
|
MyObject1[6]
|
||||||
|
### ref<Object> @ 0x7fff136845c8 destroyed
|
||||||
|
MyObject1[6]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0
|
||||||
|
### ref<MyObject1> @ 0x7fff136845a8 created via copy constructor with pointer 0xee95a0
|
||||||
|
MyObject1[6]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845a8 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0
|
||||||
|
MyObject1[6]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0
|
||||||
|
MyObject1[6]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 destroyed
|
||||||
7
|
7
|
||||||
<example.MyObject2 object at 0x7f830b50b330>
|
### Object @ 0xee97f0 created via default constructor
|
||||||
<example.MyObject2 object at 0x7f830b50bdb0>
|
### MyObject1 @ 0xee97f0 created MyObject1[7]
|
||||||
<example.MyObject2 object at 0x7f83098f6330>
|
### ref<MyObject1> @ 0x7f6a2c32ab08 created from pointer 0xee97f0
|
||||||
<example.MyObject3 object at 0x7f830b50b330>
|
MyObject1[7]
|
||||||
<example.MyObject3 object at 0x7f830b50bdb0>
|
### MyObject1 @ 0xee97f0 destroyed
|
||||||
<example.MyObject3 object at 0x7f83098f6370>
|
### Object @ 0xee97f0 destroyed
|
||||||
MyObject3[9] destructor
|
### ref<MyObject1> @ 0x7f6a2c32ab08 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### Object @ 0xee99e0 created via default constructor
|
||||||
|
### MyObject1 @ 0xee99e0 created MyObject1[7]
|
||||||
|
### ref<MyObject1> @ 0x7f6a2c32ab08 created from pointer 0xee99e0
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee99e0
|
||||||
|
### ref<MyObject1> @ 0x7fff136845a8 created via copy constructor with pointer 0xee99e0
|
||||||
|
MyObject1[7]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845a8 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 destroyed
|
||||||
|
### MyObject1 @ 0xee99e0 destroyed
|
||||||
|
### Object @ 0xee99e0 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7f6a2c32ab08 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### Object @ 0xee97f0 created via default constructor
|
||||||
|
### MyObject1 @ 0xee97f0 created MyObject1[7]
|
||||||
|
### ref<MyObject1> @ 0x7f6a2c32ab08 created from pointer 0xee97f0
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee97f0
|
||||||
|
MyObject1[7]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 destroyed
|
||||||
|
### MyObject1 @ 0xee97f0 destroyed
|
||||||
|
### Object @ 0xee97f0 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7f6a2c32ab08 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
|
||||||
|
### Object @ 0xee99e0 created via default constructor
|
||||||
|
### MyObject1 @ 0xee99e0 created MyObject1[7]
|
||||||
|
### ref<MyObject1> @ 0x7f6a2c32ab08 created from pointer 0xee99e0
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee99e0
|
||||||
|
MyObject1[7]
|
||||||
|
### ref<MyObject1> @ 0x7fff136845c8 destroyed
|
||||||
|
### MyObject1 @ 0xee99e0 destroyed
|
||||||
|
### Object @ 0xee99e0 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7f6a2c32ab08 destroyed
|
||||||
|
### MyObject1 @ 0xee95a0 destroyed
|
||||||
|
### Object @ 0xee95a0 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7f6a2c32ab38 destroyed
|
||||||
|
### MyObject1 @ 0xee8470 destroyed
|
||||||
|
### Object @ 0xee8470 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7f6a2c32aad8 destroyed
|
||||||
|
### MyObject1 @ 0xee8310 destroyed
|
||||||
|
### Object @ 0xee8310 destroyed
|
||||||
|
### ref<MyObject1> @ 0x7f6a2e03c4a8 destroyed
|
||||||
|
### MyObject2 @ 0xe43f50 created MyObject2[8]
|
||||||
|
### MyObject2 @ 0xee95a0 created MyObject2[6]
|
||||||
|
### MyObject2 @ 0xee95d0 created MyObject2[7]
|
||||||
|
<example.MyObject2 object at 0x7f6a2dfc8768>
|
||||||
|
MyObject2[8]
|
||||||
|
MyObject2[8]
|
||||||
|
MyObject2[8]
|
||||||
|
MyObject2[8]
|
||||||
|
<example.MyObject2 object at 0x7f6a2dfc86c0>
|
||||||
|
MyObject2[6]
|
||||||
|
MyObject2[6]
|
||||||
|
MyObject2[6]
|
||||||
|
MyObject2[6]
|
||||||
|
<example.MyObject2 object at 0x7f6a2c32d030>
|
||||||
|
MyObject2[7]
|
||||||
|
MyObject2[7]
|
||||||
|
MyObject2[7]
|
||||||
|
MyObject2[7]
|
||||||
|
### MyObject2 @ 0xee95a0 destroyed
|
||||||
|
### MyObject2 @ 0xe43f50 destroyed
|
||||||
|
### MyObject3 @ 0xee9ac0 created MyObject3[9]
|
||||||
|
### MyObject3 @ 0xe43f90 created MyObject3[8]
|
||||||
|
### MyObject3 @ 0xeea7d0 created MyObject3[9]
|
||||||
|
### MyObject2 @ 0xee95d0 destroyed
|
||||||
|
<example.MyObject3 object at 0x7f6a2dfc8768>
|
||||||
|
MyObject3[9]
|
||||||
|
MyObject3[9]
|
||||||
|
MyObject3[9]
|
||||||
|
MyObject3[9]
|
||||||
|
<example.MyObject3 object at 0x7f6a2dfc86c0>
|
||||||
|
MyObject3[8]
|
||||||
|
MyObject3[8]
|
||||||
|
MyObject3[8]
|
||||||
|
MyObject3[8]
|
||||||
|
<example.MyObject3 object at 0x7f6a2c32d068>
|
||||||
|
MyObject3[9]
|
||||||
|
MyObject3[9]
|
||||||
|
MyObject3[9]
|
||||||
|
MyObject3[9]
|
||||||
|
### MyObject3 @ 0xe43f90 destroyed
|
||||||
|
### MyObject3 @ 0xee9ac0 destroyed
|
||||||
|
Instances not destroyed: [0, 0, 0, 1, 0]
|
||||||
|
### MyObject3 @ 0xeea7d0 destroyed
|
||||||
|
Instances not destroyed: [0, 0, 0, 0, 0]
|
||||||
|
Object value constructions: [[], ['MyObject1[1]', 'MyObject1[2]', 'MyObject1[3]', 'MyObject1[4]', 'MyObject1[5]', 'MyObject1[6]', 'MyObject1[7]', 'MyObject1[7]', 'MyObject1[7]', 'MyObject1[7]'], ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]'], ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]'], ['from pointer', 'from pointer', 'from pointer', 'from pointer', 'from pointer', 'from pointer', 'from pointer', 'from pointer', 'from pointer', 'from pointer']]
|
||||||
|
Default constructions: [10, 0, 0, 0, 30]
|
||||||
|
Copy constructions: [0, 0, 0, 0, 12]
|
||||||
|
Copy assignments: [0, 0, 0, 0, 30]
|
||||||
|
Move assignments: [0, 0, 0, 0, 0]
|
||||||
|
@ -8,18 +8,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "example.h"
|
#include "example.h"
|
||||||
|
#include "constructor-stats.h"
|
||||||
#include <pybind11/functional.h>
|
#include <pybind11/functional.h>
|
||||||
|
|
||||||
/* This is an example class that we'll want to be able to extend from Python */
|
/* This is an example class that we'll want to be able to extend from Python */
|
||||||
class ExampleVirt {
|
class ExampleVirt {
|
||||||
public:
|
public:
|
||||||
ExampleVirt(int state) : state(state) {
|
ExampleVirt(int state) : state(state) { print_created(this, state); }
|
||||||
cout << "Constructing ExampleVirt.." << endl;
|
ExampleVirt(const ExampleVirt &e) : state(e.state) { print_copy_created(this); }
|
||||||
}
|
ExampleVirt(ExampleVirt &&e) : state(e.state) { print_move_created(this); e.state = 0; }
|
||||||
|
~ExampleVirt() { print_destroyed(this); }
|
||||||
~ExampleVirt() {
|
|
||||||
cout << "Destructing ExampleVirt.." << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int run(int value) {
|
virtual int run(int value) {
|
||||||
std::cout << "Original implementation of ExampleVirt::run(state=" << state
|
std::cout << "Original implementation of ExampleVirt::run(state=" << state
|
||||||
@ -71,8 +69,8 @@ public:
|
|||||||
|
|
||||||
class NonCopyable {
|
class NonCopyable {
|
||||||
public:
|
public:
|
||||||
NonCopyable(int a, int b) : value{new int(a*b)} {}
|
NonCopyable(int a, int b) : value{new int(a*b)} { print_created(this, a, b); }
|
||||||
NonCopyable(NonCopyable &&) = default;
|
NonCopyable(NonCopyable &&o) { value = std::move(o.value); print_move_created(this); }
|
||||||
NonCopyable(const NonCopyable &) = delete;
|
NonCopyable(const NonCopyable &) = delete;
|
||||||
NonCopyable() = delete;
|
NonCopyable() = delete;
|
||||||
void operator=(const NonCopyable &) = delete;
|
void operator=(const NonCopyable &) = delete;
|
||||||
@ -80,7 +78,7 @@ public:
|
|||||||
std::string get_value() const {
|
std::string get_value() const {
|
||||||
if (value) return std::to_string(*value); else return "(null)";
|
if (value) return std::to_string(*value); else return "(null)";
|
||||||
}
|
}
|
||||||
~NonCopyable() { std::cout << "NonCopyable destructor @ " << this << "; value = " << get_value() << std::endl; }
|
~NonCopyable() { print_destroyed(this); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<int> value;
|
std::unique_ptr<int> value;
|
||||||
@ -90,11 +88,11 @@ private:
|
|||||||
// when it is not referenced elsewhere, but copied if it is still referenced.
|
// when it is not referenced elsewhere, but copied if it is still referenced.
|
||||||
class Movable {
|
class Movable {
|
||||||
public:
|
public:
|
||||||
Movable(int a, int b) : value{a+b} {}
|
Movable(int a, int b) : value{a+b} { print_created(this, a, b); }
|
||||||
Movable(const Movable &m) { value = m.value; std::cout << "Movable @ " << this << " copy constructor" << std::endl; }
|
Movable(const Movable &m) { value = m.value; print_copy_created(this); }
|
||||||
Movable(Movable &&m) { value = std::move(m.value); std::cout << "Movable @ " << this << " move constructor" << std::endl; }
|
Movable(Movable &&m) { value = std::move(m.value); print_move_created(this); }
|
||||||
int get_value() const { return value; }
|
int get_value() const { return value; }
|
||||||
~Movable() { std::cout << "Movable destructor @ " << this << "; value = " << get_value() << std::endl; }
|
~Movable() { print_destroyed(this); }
|
||||||
private:
|
private:
|
||||||
int value;
|
int value;
|
||||||
};
|
};
|
||||||
@ -305,5 +303,6 @@ void init_ex_virtual_functions(py::module &m) {
|
|||||||
m.def("runExampleVirtBool", &runExampleVirtBool);
|
m.def("runExampleVirtBool", &runExampleVirtBool);
|
||||||
m.def("runExampleVirtVirtual", &runExampleVirtVirtual);
|
m.def("runExampleVirtVirtual", &runExampleVirtVirtual);
|
||||||
|
|
||||||
|
m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
|
||||||
initialize_inherited_virtuals(m);
|
initialize_inherited_virtuals(m);
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,6 @@ print(runExampleVirt(ex12p, 20))
|
|||||||
print(runExampleVirtBool(ex12p))
|
print(runExampleVirtBool(ex12p))
|
||||||
runExampleVirtVirtual(ex12p)
|
runExampleVirtVirtual(ex12p)
|
||||||
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
class VI_AR(A_Repeat):
|
class VI_AR(A_Repeat):
|
||||||
def unlucky_number(self):
|
def unlucky_number(self):
|
||||||
return 99
|
return 99
|
||||||
@ -122,3 +120,16 @@ try:
|
|||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
# Don't print the exception message here because it differs under debug/non-debug mode
|
# Don't print the exception message here because it differs under debug/non-debug mode
|
||||||
print("Caught expected exception")
|
print("Caught expected exception")
|
||||||
|
|
||||||
|
from example import ConstructorStats
|
||||||
|
del ex12
|
||||||
|
del ex12p
|
||||||
|
del obj
|
||||||
|
del ncv1
|
||||||
|
del ncv2
|
||||||
|
cstats = [ConstructorStats.get(ExampleVirt), ConstructorStats.get(NonCopyable), ConstructorStats.get(Movable)]
|
||||||
|
print("Instances not destroyed:", [x.alive() for x in cstats])
|
||||||
|
print("Constructor values:", [x.values() for x in cstats])
|
||||||
|
print("Copy constructions:", [x.copy_constructions for x in cstats])
|
||||||
|
print("Move constructions:", [cstats[i].move_constructions >= 1 for i in range(1, len(cstats))])
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
Constructing ExampleVirt..
|
### ExampleVirt @ 0x2073a90 created 10
|
||||||
Original implementation of ExampleVirt::run(state=10, value=20)
|
Original implementation of ExampleVirt::run(state=10, value=20)
|
||||||
30
|
30
|
||||||
Caught expected exception: Tried to call pure virtual function "ExampleVirt::pure_virtual"
|
Caught expected exception: Tried to call pure virtual function "ExampleVirt::pure_virtual"
|
||||||
Constructing ExampleVirt..
|
### ExampleVirt @ 0x2076a00 created 11
|
||||||
ExtendedExampleVirt::run(20), calling parent..
|
ExtendedExampleVirt::run(20), calling parent..
|
||||||
Original implementation of ExampleVirt::run(state=11, value=21)
|
Original implementation of ExampleVirt::run(state=11, value=21)
|
||||||
32
|
32
|
||||||
@ -78,20 +78,29 @@ VI_DT says: quack quack quack
|
|||||||
Unlucky = 1234
|
Unlucky = 1234
|
||||||
Lucky = -4.25
|
Lucky = -4.25
|
||||||
2^2 * 3^2 =
|
2^2 * 3^2 =
|
||||||
NonCopyable destructor @ 0x1a6c3f0; value = (null)
|
### NonCopyable @ 0x207df10 created 4 9
|
||||||
|
### NonCopyable @ 0x7ffcfe866228 created via move constructor
|
||||||
|
### NonCopyable @ 0x207df10 destroyed
|
||||||
36
|
36
|
||||||
NonCopyable destructor @ 0x7ffc6d1fbaa8; value = 36
|
### NonCopyable @ 0x7ffcfe866228 destroyed
|
||||||
4 + 5 =
|
4 + 5 =
|
||||||
Movable @ 0x7ffc6d1fbacc copy constructor
|
### Movable @ 0x207e230 created 4 5
|
||||||
|
### Movable @ 0x7ffcfe86624c created via copy constructor
|
||||||
9
|
9
|
||||||
Movable destructor @ 0x7ffc6d1fbacc; value = 9
|
### Movable @ 0x7ffcfe86624c destroyed
|
||||||
7 + 7 =
|
7 + 7 =
|
||||||
Movable @ 0x7ffc6d1fbacc move constructor
|
### Movable @ 0x20259e0 created 7 7
|
||||||
Movable destructor @ 0x1a6c4d0; value = 14
|
### Movable @ 0x7ffcfe86624c created via move constructor
|
||||||
|
### Movable @ 0x20259e0 destroyed
|
||||||
14
|
14
|
||||||
Movable destructor @ 0x7ffc6d1fbacc; value = 14
|
### Movable @ 0x7ffcfe86624c destroyed
|
||||||
|
### NonCopyable @ 0x2025a00 created 9 9
|
||||||
Caught expected exception
|
Caught expected exception
|
||||||
NonCopyable destructor @ 0x29a64b0; value = 81
|
### ExampleVirt @ 0x2073a90 destroyed
|
||||||
Movable destructor @ 0x1a6c410; value = 9
|
### ExampleVirt @ 0x2076a00 destroyed
|
||||||
Destructing ExampleVirt..
|
### Movable @ 0x207e230 destroyed
|
||||||
Destructing ExampleVirt..
|
### NonCopyable @ 0x2025a00 destroyed
|
||||||
|
Instances not destroyed: [0, 0, 0]
|
||||||
|
Constructor values: [['10', '11'], ['4', '9', '9', '9'], ['4', '5', '7', '7']]
|
||||||
|
Copy constructions: [0, 0, 1]
|
||||||
|
Move constructions: [True, True]
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "example.h"
|
#include "example.h"
|
||||||
|
#include "constructor-stats.h"
|
||||||
|
|
||||||
void init_ex_methods_and_attributes(py::module &);
|
void init_ex_methods_and_attributes(py::module &);
|
||||||
void init_ex_python_types(py::module &);
|
void init_ex_python_types(py::module &);
|
||||||
@ -34,9 +35,24 @@ void init_issues(py::module &);
|
|||||||
void init_eigen(py::module &);
|
void init_eigen(py::module &);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void bind_ConstructorStats(py::module &m) {
|
||||||
|
py::class_<ConstructorStats>(m, "ConstructorStats")
|
||||||
|
.def("alive", &ConstructorStats::alive)
|
||||||
|
.def("values", &ConstructorStats::values)
|
||||||
|
.def_readwrite("default_constructions", &ConstructorStats::default_constructions)
|
||||||
|
.def_readwrite("copy_assignments", &ConstructorStats::copy_assignments)
|
||||||
|
.def_readwrite("move_assignments", &ConstructorStats::move_assignments)
|
||||||
|
.def_readwrite("copy_constructions", &ConstructorStats::copy_constructions)
|
||||||
|
.def_readwrite("move_constructions", &ConstructorStats::move_constructions)
|
||||||
|
.def_static("get", (ConstructorStats &(*)(py::object)) &ConstructorStats::get, py::return_value_policy::reference_internal)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
PYBIND11_PLUGIN(example) {
|
PYBIND11_PLUGIN(example) {
|
||||||
py::module m("example", "pybind example plugin");
|
py::module m("example", "pybind example plugin");
|
||||||
|
|
||||||
|
bind_ConstructorStats(m);
|
||||||
|
|
||||||
init_ex_methods_and_attributes(m);
|
init_ex_methods_and_attributes(m);
|
||||||
init_ex_python_types(m);
|
init_ex_python_types(m);
|
||||||
init_ex_operator_overloading(m);
|
init_ex_operator_overloading(m);
|
||||||
|
@ -8,11 +8,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "example.h"
|
#include "example.h"
|
||||||
|
#include "constructor-stats.h"
|
||||||
#include <pybind11/stl.h>
|
#include <pybind11/stl.h>
|
||||||
#include <pybind11/operators.h>
|
#include <pybind11/operators.h>
|
||||||
|
|
||||||
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
||||||
|
|
||||||
|
#define TRACKERS(CLASS) CLASS() { print_default_created(this); } ~CLASS() { print_destroyed(this); }
|
||||||
|
struct NestABase { int value = -2; TRACKERS(NestABase) };
|
||||||
|
struct NestA : NestABase { int value = 3; NestA& operator+=(int i) { value += i; return *this; } TRACKERS(NestA) };
|
||||||
|
struct NestB { NestA a; int value = 4; NestB& operator-=(int i) { value -= i; return *this; } TRACKERS(NestB) };
|
||||||
|
struct NestC { NestB b; int value = 5; NestC& operator*=(int i) { value *= i; return *this; } TRACKERS(NestC) };
|
||||||
|
|
||||||
void init_issues(py::module &m) {
|
void init_issues(py::module &m) {
|
||||||
py::module m2 = m.def_submodule("issues");
|
py::module m2 = m.def_submodule("issues");
|
||||||
|
|
||||||
@ -159,12 +166,6 @@ void init_issues(py::module &m) {
|
|||||||
;
|
;
|
||||||
|
|
||||||
// Issue #328: first member in a class can't be used in operators
|
// Issue #328: first member in a class can't be used in operators
|
||||||
#define TRACKERS(CLASS) CLASS() { std::cout << #CLASS "@" << this << " constructor\n"; } \
|
|
||||||
~CLASS() { std::cout << #CLASS "@" << this << " destructor\n"; }
|
|
||||||
struct NestABase { int value = -2; TRACKERS(NestABase) };
|
|
||||||
struct NestA : NestABase { int value = 3; NestA& operator+=(int i) { value += i; return *this; } TRACKERS(NestA) };
|
|
||||||
struct NestB { NestA a; int value = 4; NestB& operator-=(int i) { value -= i; return *this; } TRACKERS(NestB) };
|
|
||||||
struct NestC { NestB b; int value = 5; NestC& operator*=(int i) { value *= i; return *this; } TRACKERS(NestC) };
|
|
||||||
py::class_<NestABase>(m2, "NestABase").def(py::init<>()).def_readwrite("value", &NestABase::value);
|
py::class_<NestABase>(m2, "NestABase").def(py::init<>()).def_readwrite("value", &NestABase::value);
|
||||||
py::class_<NestA>(m2, "NestA").def(py::init<>()).def(py::self += int())
|
py::class_<NestA>(m2, "NestA").def(py::init<>()).def(py::self += int())
|
||||||
.def("as_base", [](NestA &a) -> NestABase& { return (NestABase&) a; }, py::return_value_policy::reference_internal);
|
.def("as_base", [](NestA &a) -> NestABase& { return (NestABase&) a; }, py::return_value_policy::reference_internal);
|
||||||
|
@ -24,15 +24,15 @@ Failed as expected: Incompatible constructor arguments. The following argument t
|
|||||||
1. example.issues.StrIssue(arg0: int)
|
1. example.issues.StrIssue(arg0: int)
|
||||||
2. example.issues.StrIssue()
|
2. example.issues.StrIssue()
|
||||||
Invoked with: no, such, constructor
|
Invoked with: no, such, constructor
|
||||||
NestABase@0x1152940 constructor
|
### NestABase @ 0x15eb630 created via default constructor
|
||||||
NestA@0x1152940 constructor
|
### NestA @ 0x15eb630 created via default constructor
|
||||||
NestABase@0x11f9350 constructor
|
### NestABase @ 0x1704000 created via default constructor
|
||||||
NestA@0x11f9350 constructor
|
### NestA @ 0x1704000 created via default constructor
|
||||||
NestB@0x11f9350 constructor
|
### NestB @ 0x1704000 created via default constructor
|
||||||
NestABase@0x112d0d0 constructor
|
### NestABase @ 0x1633110 created via default constructor
|
||||||
NestA@0x112d0d0 constructor
|
### NestA @ 0x1633110 created via default constructor
|
||||||
NestB@0x112d0d0 constructor
|
### NestB @ 0x1633110 created via default constructor
|
||||||
NestC@0x112d0d0 constructor
|
### NestC @ 0x1633110 created via default constructor
|
||||||
13
|
13
|
||||||
103
|
103
|
||||||
1003
|
1003
|
||||||
@ -43,13 +43,13 @@ NestC@0x112d0d0 constructor
|
|||||||
42
|
42
|
||||||
-2
|
-2
|
||||||
42
|
42
|
||||||
NestC@0x112d0d0 destructor
|
### NestC @ 0x1633110 destroyed
|
||||||
NestB@0x112d0d0 destructor
|
### NestB @ 0x1633110 destroyed
|
||||||
NestA@0x112d0d0 destructor
|
### NestA @ 0x1633110 destroyed
|
||||||
NestABase@0x112d0d0 destructor
|
### NestABase @ 0x1633110 destroyed
|
||||||
42
|
42
|
||||||
NestA@0x1152940 destructor
|
### NestA @ 0x15eb630 destroyed
|
||||||
NestABase@0x1152940 destructor
|
### NestABase @ 0x15eb630 destroyed
|
||||||
NestB@0x11f9350 destructor
|
### NestB @ 0x1704000 destroyed
|
||||||
NestA@0x11f9350 destructor
|
### NestA @ 0x1704000 destroyed
|
||||||
NestABase@0x11f9350 destructor
|
### NestABase @ 0x1704000 destroyed
|
||||||
|
@ -2,15 +2,16 @@
|
|||||||
#define __OBJECT_H
|
#define __OBJECT_H
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include "constructor-stats.h"
|
||||||
|
|
||||||
/// Reference counted object base class
|
/// Reference counted object base class
|
||||||
class Object {
|
class Object {
|
||||||
public:
|
public:
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
Object() { }
|
Object() { print_default_created(this); }
|
||||||
|
|
||||||
/// Copy constructor
|
/// Copy constructor
|
||||||
Object(const Object &) : m_refCount(0) {}
|
Object(const Object &) : m_refCount(0) { print_copy_created(this); }
|
||||||
|
|
||||||
/// Return the current reference count
|
/// Return the current reference count
|
||||||
int getRefCount() const { return m_refCount; };
|
int getRefCount() const { return m_refCount; };
|
||||||
@ -37,11 +38,17 @@ protected:
|
|||||||
/** \brief Virtual protected deconstructor.
|
/** \brief Virtual protected deconstructor.
|
||||||
* (Will only be called by \ref ref)
|
* (Will only be called by \ref ref)
|
||||||
*/
|
*/
|
||||||
virtual ~Object() { }
|
virtual ~Object() { print_destroyed(this); }
|
||||||
private:
|
private:
|
||||||
mutable std::atomic<int> m_refCount { 0 };
|
mutable std::atomic<int> m_refCount { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Tag class used to track constructions of ref objects. When we track constructors, below, we
|
||||||
|
// track and print out the actual class (e.g. ref<MyObject>), and *also* add a fake tracker for
|
||||||
|
// ref_tag. This lets us check that the total number of ref<Anything> constructors/destructors is
|
||||||
|
// correct without having to check each individual ref<Whatever> type individually.
|
||||||
|
class ref_tag {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Reference counting helper
|
* \brief Reference counting helper
|
||||||
*
|
*
|
||||||
@ -55,37 +62,43 @@ private:
|
|||||||
template <typename T> class ref {
|
template <typename T> class ref {
|
||||||
public:
|
public:
|
||||||
/// Create a nullptr reference
|
/// Create a nullptr reference
|
||||||
ref() : m_ptr(nullptr) { std::cout << "Created empty ref" << std::endl; }
|
ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); }
|
||||||
|
|
||||||
/// Construct a reference from a pointer
|
/// Construct a reference from a pointer
|
||||||
ref(T *ptr) : m_ptr(ptr) {
|
ref(T *ptr) : m_ptr(ptr) {
|
||||||
std::cout << "Initialized ref from pointer " << ptr<< std::endl;
|
|
||||||
if (m_ptr) ((Object *) m_ptr)->incRef();
|
if (m_ptr) ((Object *) m_ptr)->incRef();
|
||||||
|
|
||||||
|
print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy constructor
|
/// Copy constructor
|
||||||
ref(const ref &r) : m_ptr(r.m_ptr) {
|
ref(const ref &r) : m_ptr(r.m_ptr) {
|
||||||
std::cout << "Initialized ref from ref " << r.m_ptr << std::endl;
|
|
||||||
if (m_ptr)
|
if (m_ptr)
|
||||||
((Object *) m_ptr)->incRef();
|
((Object *) m_ptr)->incRef();
|
||||||
|
|
||||||
|
print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move constructor
|
/// Move constructor
|
||||||
ref(ref &&r) : m_ptr(r.m_ptr) {
|
ref(ref &&r) : m_ptr(r.m_ptr) {
|
||||||
std::cout << "Initialized ref with move from ref " << r.m_ptr << std::endl;
|
|
||||||
r.m_ptr = nullptr;
|
r.m_ptr = nullptr;
|
||||||
|
|
||||||
|
print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destroy this reference
|
/// Destroy this reference
|
||||||
~ref() {
|
~ref() {
|
||||||
std::cout << "Destructing ref " << m_ptr << std::endl;
|
|
||||||
if (m_ptr)
|
if (m_ptr)
|
||||||
((Object *) m_ptr)->decRef();
|
((Object *) m_ptr)->decRef();
|
||||||
|
|
||||||
|
print_destroyed(this); track_destroyed((ref_tag*) this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move another reference into the current one
|
/// Move another reference into the current one
|
||||||
ref& operator=(ref&& r) {
|
ref& operator=(ref&& r) {
|
||||||
std::cout << "Move-assigning ref " << r.m_ptr << std::endl;
|
print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this);
|
||||||
|
|
||||||
if (*this == r)
|
if (*this == r)
|
||||||
return *this;
|
return *this;
|
||||||
if (m_ptr)
|
if (m_ptr)
|
||||||
@ -97,7 +110,8 @@ public:
|
|||||||
|
|
||||||
/// Overwrite this reference with another reference
|
/// Overwrite this reference with another reference
|
||||||
ref& operator=(const ref& r) {
|
ref& operator=(const ref& r) {
|
||||||
std::cout << "Assigning ref " << r.m_ptr << std::endl;
|
print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this);
|
||||||
|
|
||||||
if (m_ptr == r.m_ptr)
|
if (m_ptr == r.m_ptr)
|
||||||
return *this;
|
return *this;
|
||||||
if (m_ptr)
|
if (m_ptr)
|
||||||
@ -110,7 +124,8 @@ public:
|
|||||||
|
|
||||||
/// Overwrite this reference with a pointer to another object
|
/// Overwrite this reference with a pointer to another object
|
||||||
ref& operator=(T *ptr) {
|
ref& operator=(T *ptr) {
|
||||||
std::cout << "Assigning ptr " << ptr << " to ref" << std::endl;
|
print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer");
|
||||||
|
|
||||||
if (m_ptr == ptr)
|
if (m_ptr == ptr)
|
||||||
return *this;
|
return *this;
|
||||||
if (m_ptr)
|
if (m_ptr)
|
||||||
|
@ -9,14 +9,16 @@ remove_long_marker = re.compile(r'([0-9])L')
|
|||||||
remove_hex = re.compile(r'0x[0-9a-fA-F]+')
|
remove_hex = re.compile(r'0x[0-9a-fA-F]+')
|
||||||
shorten_floats = re.compile(r'([1-9][0-9]*\.[0-9]{4})[0-9]*')
|
shorten_floats = re.compile(r'([1-9][0-9]*\.[0-9]{4})[0-9]*')
|
||||||
|
|
||||||
relaxed = False
|
|
||||||
|
|
||||||
def sanitize(lines):
|
def sanitize(lines):
|
||||||
lines = lines.split('\n')
|
lines = lines.split('\n')
|
||||||
for i in range(len(lines)):
|
for i in range(len(lines)):
|
||||||
line = lines[i]
|
line = lines[i]
|
||||||
if line.startswith(" |"):
|
if line.startswith(" |"):
|
||||||
line = ""
|
line = ""
|
||||||
|
if line.startswith("### "):
|
||||||
|
# Constructor/destructor output. Useful for example, but unreliable across compilers;
|
||||||
|
# testing of proper construction/destruction occurs with ConstructorStats mechanism instead
|
||||||
|
line = ""
|
||||||
line = remove_unicode_marker.sub(r'\1', line)
|
line = remove_unicode_marker.sub(r'\1', line)
|
||||||
line = remove_long_marker.sub(r'\1', line)
|
line = remove_long_marker.sub(r'\1', line)
|
||||||
line = remove_hex.sub(r'0', line)
|
line = remove_hex.sub(r'0', line)
|
||||||
@ -28,13 +30,6 @@ def sanitize(lines):
|
|||||||
line = line.replace('example.EMode', 'EMode')
|
line = line.replace('example.EMode', 'EMode')
|
||||||
line = line.replace('method of builtins.PyCapsule instance', '')
|
line = line.replace('method of builtins.PyCapsule instance', '')
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if relaxed:
|
|
||||||
lower = line.lower()
|
|
||||||
# The precise pattern of allocations and deallocations is dependent on the compiler
|
|
||||||
# and optimization level, so we unfortunately can't reliably check it in this kind of test case
|
|
||||||
if 'constructor' in lower or 'destructor' in lower \
|
|
||||||
or 'ref' in lower or 'freeing' in lower:
|
|
||||||
line = ""
|
|
||||||
lines[i] = line
|
lines[i] = line
|
||||||
|
|
||||||
return '\n'.join(sorted([l for l in lines if l != ""]))
|
return '\n'.join(sorted([l for l in lines if l != ""]))
|
||||||
@ -44,16 +39,12 @@ if path != '':
|
|||||||
os.chdir(path)
|
os.chdir(path)
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
print("Syntax: %s [--relaxed] <test name>" % sys.argv[0])
|
print("Syntax: %s <test name>" % sys.argv[0])
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
if len(sys.argv) == 3 and sys.argv[1] == '--relaxed':
|
|
||||||
del sys.argv[1]
|
|
||||||
relaxed = True
|
|
||||||
|
|
||||||
name = sys.argv[1]
|
name = sys.argv[1]
|
||||||
try:
|
try:
|
||||||
output_bytes = subprocess.check_output([sys.executable, name + ".py"],
|
output_bytes = subprocess.check_output([sys.executable, "-u", name + ".py"],
|
||||||
stderr=subprocess.STDOUT)
|
stderr=subprocess.STDOUT)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
if e.returncode == 99:
|
if e.returncode == 99:
|
||||||
|
Loading…
Reference in New Issue
Block a user