mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 21:25:13 +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()
|
||||
|
||||
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})
|
||||
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 "constructor-stats.h"
|
||||
|
||||
class Matrix {
|
||||
public:
|
||||
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];
|
||||
memset(m_data, 0, sizeof(float) * rows * 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];
|
||||
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) {
|
||||
std::cout << "Move constructor: Creating a " << m_rows << "x" << m_cols << " matrix " << std::endl;
|
||||
print_move_created(this);
|
||||
s.m_rows = 0;
|
||||
s.m_cols = 0;
|
||||
s.m_data = nullptr;
|
||||
}
|
||||
|
||||
~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;
|
||||
}
|
||||
|
||||
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;
|
||||
m_rows = s.m_rows;
|
||||
m_cols = s.m_cols;
|
||||
@ -46,7 +47,7 @@ public:
|
||||
}
|
||||
|
||||
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) {
|
||||
delete[] 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) }
|
||||
);
|
||||
});
|
||||
})
|
||||
;
|
||||
}
|
||||
|
@ -30,3 +30,16 @@ for i in range(m4.rows()):
|
||||
for j in range(m4.cols()):
|
||||
print(m4[i, j], end = ' ')
|
||||
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
|
||||
4.0
|
||||
[[ 0. 0. 0. 0. 0.]
|
||||
@ -10,8 +10,15 @@ Value constructor: Creating a 5x5 matrix
|
||||
5.0
|
||||
[[ 1. 2. 3.]
|
||||
[ 4. 5. 6.]]
|
||||
Value constructor: Creating a 2x3 matrix
|
||||
### Matrix @ 0x1fa8cf0 created 2x3 matrix
|
||||
1.0 2.0 3.0
|
||||
4.0 5.0 6.0
|
||||
Freeing a 2x3 matrix
|
||||
Freeing a 5x5 matrix
|
||||
Instances not destroyed: 2
|
||||
### 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 "constructor-stats.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) {
|
||||
m.def("test_callback1", &test_callback1);
|
||||
m.def("test_callback2", &test_callback2);
|
||||
@ -66,21 +82,6 @@ void init_ex_callbacks(py::module &m) {
|
||||
|
||||
/* 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)> {
|
||||
Payload p;
|
||||
|
||||
@ -94,4 +95,6 @@ void init_ex_callbacks(py::module &m) {
|
||||
m.def("dummy_function2", &dummy_function2);
|
||||
m.def("roundtrip", &roundtrip);
|
||||
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()
|
||||
|
||||
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_function2
|
||||
from example import test_dummy_function
|
||||
|
@ -7,7 +7,7 @@ Molly is a dog
|
||||
Woof!
|
||||
The following error is expected: Incompatible function arguments. The following argument types are supported:
|
||||
1. (arg0: example.Dog) -> None
|
||||
Invoked with: <example.Pet object at 0>
|
||||
Invoked with: <example.Pet object at 0x7ffaf4b00db0>
|
||||
Callback function 1 called!
|
||||
False
|
||||
Callback function 2 called : Hello, x, True, 5
|
||||
@ -19,12 +19,15 @@ False
|
||||
func(43) = 44
|
||||
func(43) = 44
|
||||
func(number=43) = 44
|
||||
Payload constructor
|
||||
Payload copy constructor
|
||||
Payload move constructor
|
||||
Payload destructor
|
||||
Payload destructor
|
||||
Payload destructor
|
||||
### Payload @ 0x7ffdcee09c80 created via default constructor
|
||||
### Payload @ 0x7ffdcee09c88 created via copy constructor
|
||||
### Payload @ 0xb54500 created via move constructor
|
||||
### Payload @ 0x7ffdcee09c88 destroyed
|
||||
### Payload @ 0x7ffdcee09c80 destroyed
|
||||
### Payload @ 0xb54500 destroyed
|
||||
Payload instances not destroyed: 0
|
||||
Copy constructions: 1
|
||||
Move constructions: True
|
||||
argument matches dummy_function
|
||||
eval(1) = 2
|
||||
roundtrip..
|
||||
@ -36,6 +39,7 @@ could not convert to a function pointer.
|
||||
All OK!
|
||||
could not convert to a function pointer.
|
||||
All OK!
|
||||
|
||||
test_callback3(arg0: Callable[[int], int]) -> None
|
||||
|
||||
test_callback4() -> Callable[[int], int]
|
||||
|
||||
|
@ -8,32 +8,25 @@
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include "example.h"
|
||||
#include "constructor-stats.h"
|
||||
|
||||
class ExampleMandA {
|
||||
public:
|
||||
ExampleMandA() {
|
||||
cout << "Called ExampleMandA default constructor.." << endl;
|
||||
}
|
||||
ExampleMandA(int value) : value(value) {
|
||||
cout << "Called ExampleMandA constructor with value " << value << ".." << endl;
|
||||
}
|
||||
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;
|
||||
}
|
||||
ExampleMandA() { print_default_created(this); }
|
||||
ExampleMandA(int value) : value(value) { print_created(this, value); }
|
||||
ExampleMandA(const ExampleMandA &e) : value(e.value) { print_copy_created(this); }
|
||||
ExampleMandA(ExampleMandA &&e) : value(e.value) { print_move_created(this); }
|
||||
~ExampleMandA() { print_destroyed(this); }
|
||||
|
||||
std::string toString() {
|
||||
return "ExampleMandA[value=" + std::to_string(value) + "]";
|
||||
}
|
||||
|
||||
void operator=(const ExampleMandA &e) { cout << "Assignment operator" << endl; value = e.value; }
|
||||
void operator=(ExampleMandA &&e) { cout << "Move assignment operator" << endl; value = e.value; e.value = 0;}
|
||||
void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; }
|
||||
void operator=(ExampleMandA &&e) { print_move_assigned(this); value = e.value; }
|
||||
|
||||
void add1(ExampleMandA other) { value += other.value; } // passing by value
|
||||
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("internal5", &ExampleMandA::internal5)
|
||||
.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)
|
||||
instance1.value = 100
|
||||
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..
|
||||
Called ExampleMandA constructor with value 32..
|
||||
Called ExampleMandA copy constructor with value 32..
|
||||
Called ExampleMandA copy constructor with value 32..
|
||||
Called ExampleMandA destructor (32)
|
||||
Called ExampleMandA destructor (32)
|
||||
### ExampleMandA @ 0x2801910 created via default constructor
|
||||
### ExampleMandA @ 0x27fa780 created 32
|
||||
### ExampleMandA @ 0x7fff80a98a74 created via copy constructor
|
||||
### ExampleMandA @ 0x7fff80a98a78 created via copy constructor
|
||||
### ExampleMandA @ 0x7fff80a98a78 destroyed
|
||||
### ExampleMandA @ 0x7fff80a98a74 destroyed
|
||||
Instance 1: ExampleMandA[value=320]
|
||||
Instance 2: ExampleMandA[value=32]
|
||||
Called ExampleMandA copy constructor with value 320..
|
||||
Called ExampleMandA move constructor with value 320..
|
||||
Called ExampleMandA destructor (0)
|
||||
### ExampleMandA @ 0x7fff80a98a84 created via copy constructor
|
||||
### ExampleMandA @ 0x2801fd0 created via move constructor
|
||||
### ExampleMandA @ 0x7fff80a98a84 destroyed
|
||||
ExampleMandA[value=320]
|
||||
Called ExampleMandA destructor (320)
|
||||
### ExampleMandA @ 0x2801fd0 destroyed
|
||||
ExampleMandA[value=320]
|
||||
ExampleMandA[value=320]
|
||||
ExampleMandA[value=320]
|
||||
@ -22,5 +22,13 @@ ExampleMandA[value=320]
|
||||
320
|
||||
Instance 1, direct access = 320
|
||||
Instance 1: ExampleMandA[value=100]
|
||||
Called ExampleMandA destructor (32)
|
||||
Called ExampleMandA destructor (100)
|
||||
Instances not destroyed: 2
|
||||
### 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 "constructor-stats.h"
|
||||
|
||||
void submodule_func() {
|
||||
std::cout << "submodule_func()" << std::endl;
|
||||
@ -16,9 +17,10 @@ void submodule_func() {
|
||||
|
||||
class A {
|
||||
public:
|
||||
A(int v) : v(v) { std::cout << "A constructor" << std::endl; }
|
||||
~A() { std::cout << "A destructor" << std::endl; }
|
||||
A(const A&) { std::cout << "A copy constructor" << std::endl; }
|
||||
A(int v) : v(v) { print_created(this, v); }
|
||||
~A() { print_destroyed(this); }
|
||||
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) + "]"; }
|
||||
private:
|
||||
int v;
|
||||
@ -26,9 +28,10 @@ private:
|
||||
|
||||
class B {
|
||||
public:
|
||||
B() { std::cout << "B constructor" << std::endl; }
|
||||
~B() { std::cout << "B destructor" << std::endl; }
|
||||
B(const B&) { std::cout << "B copy constructor" << std::endl; }
|
||||
B() { print_default_created(this); }
|
||||
~B() { print_destroyed(this); }
|
||||
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_a2() { return a2; }
|
||||
|
||||
|
@ -28,3 +28,16 @@ print(b.get_a2())
|
||||
print(b.a2)
|
||||
|
||||
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.submodule
|
||||
submodule_func()
|
||||
A constructor
|
||||
A constructor
|
||||
B constructor
|
||||
### A @ 0x21a5bc0 created 1
|
||||
### A @ 0x21a5bc4 created 2
|
||||
### B @ 0x21a5bc0 created via default constructor
|
||||
A[1]
|
||||
A[1]
|
||||
A[2]
|
||||
A[2]
|
||||
A constructor
|
||||
A destructor
|
||||
A constructor
|
||||
A destructor
|
||||
### A @ 0x20f93b0 created 42
|
||||
### A @ 0x21a5bc0 assigned via copy assignment
|
||||
### A @ 0x20f93b0 destroyed
|
||||
### A @ 0x20f93d0 created 43
|
||||
### A @ 0x21a5bc4 assigned via copy assignment
|
||||
### A @ 0x20f93d0 destroyed
|
||||
A[42]
|
||||
A[42]
|
||||
A[43]
|
||||
A[43]
|
||||
OrderedDict([(1, 'a'), (2, 'b')])
|
||||
B destructor
|
||||
A destructor
|
||||
A destructor
|
||||
Instances not destroyed: [2, 1]
|
||||
### B @ 0x21a5bc0 destroyed
|
||||
### 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(ExampleMandA()) # Should also work for other C++ types
|
||||
from example import ConstructorStats
|
||||
print("ExampleMandA still alive:", ConstructorStats.get(ExampleMandA).alive())
|
||||
|
||||
try:
|
||||
print_void_ptr([1, 2, 3]) # This should not work
|
||||
|
@ -6,13 +6,14 @@ Opaque list: [Element 1]
|
||||
Opaque list: []
|
||||
Opaque list: [Element 1, Element 3]
|
||||
Got void ptr : 0x1234
|
||||
Called ExampleMandA default constructor..
|
||||
Got void ptr : 0x7f9ba0f3c430
|
||||
Called ExampleMandA destructor (0)
|
||||
### ExampleMandA @ 0x2ac5370 created via default constructor
|
||||
Got void ptr : 0x2ac5370
|
||||
### ExampleMandA @ 0x2ac5370 destroyed
|
||||
ExampleMandA still alive: 0
|
||||
Caught expected exception: Incompatible function arguments. The following argument types are supported:
|
||||
1. (arg0: capsule) -> None
|
||||
Invoked with: [1, 2, 3]
|
||||
None
|
||||
Got null str : 0x0
|
||||
<example.StringList object at 0x10d3277a0>
|
||||
<example.StringList object at 0x7f7ecde6fc00>
|
||||
Opaque list: [some value]
|
||||
|
@ -8,27 +8,28 @@
|
||||
*/
|
||||
|
||||
#include "example.h"
|
||||
#include "constructor-stats.h"
|
||||
#include <pybind11/operators.h>
|
||||
|
||||
class Vector2 {
|
||||
public:
|
||||
Vector2(float x, float y) : x(x), y(y) { std::cout << "Value constructor" << std::endl; }
|
||||
Vector2(const Vector2 &v) : x(v.x), y(v.y) { std::cout << "Copy constructor" << std::endl; }
|
||||
Vector2(Vector2 &&v) : x(v.x), y(v.y) { std::cout << "Move constructor" << std::endl; v.x = v.y = 0; }
|
||||
~Vector2() { std::cout << "Destructor." << 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) { print_copy_created(this); }
|
||||
Vector2(Vector2 &&v) : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; }
|
||||
~Vector2() { print_destroyed(this); }
|
||||
|
||||
std::string toString() const {
|
||||
return "[" + std::to_string(x) + ", " + std::to_string(y) + "]";
|
||||
}
|
||||
|
||||
void operator=(const Vector2 &v) {
|
||||
cout << "Assignment operator" << endl;
|
||||
print_copy_assigned(this);
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
}
|
||||
|
||||
void operator=(Vector2 &&v) {
|
||||
cout << "Move assignment operator" << endl;
|
||||
print_move_assigned(this);
|
||||
x = v.x; y = v.y; v.x = v.y = 0;
|
||||
}
|
||||
|
||||
@ -51,7 +52,6 @@ private:
|
||||
float x, y;
|
||||
};
|
||||
|
||||
|
||||
void init_ex_operator_overloading(py::module &m) {
|
||||
py::class_<Vector2>(m, "Vector2")
|
||||
.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("__str__", &Vector2::toString);
|
||||
.def("__str__", &Vector2::toString)
|
||||
;
|
||||
|
||||
m.attr("Vector") = m.attr("Vector2");
|
||||
}
|
||||
|
@ -25,3 +25,17 @@ v1 += v2
|
||||
v1 *= 2
|
||||
|
||||
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
|
||||
Value constructor
|
||||
### Vector2 @ 0x11f7830 created [1.000000, 2.000000]
|
||||
### Vector2 @ 0x11427c0 created [3.000000, -1.000000]
|
||||
v1 = [1.000000, 2.000000]
|
||||
v2 = [3.000000, -1.000000]
|
||||
Value constructor
|
||||
Move constructor
|
||||
Destructor.
|
||||
Destructor.
|
||||
### Vector2 @ 0x7ffef6b144b8 created [4.000000, 1.000000]
|
||||
### Vector2 @ 0x11f7e90 created via move constructor
|
||||
### Vector2 @ 0x7ffef6b144b8 destroyed
|
||||
### Vector2 @ 0x11f7e90 destroyed
|
||||
v1+v2 = [4.000000, 1.000000]
|
||||
Value constructor
|
||||
Move constructor
|
||||
Destructor.
|
||||
Destructor.
|
||||
### Vector2 @ 0x7ffef6b144b8 created [-2.000000, 3.000000]
|
||||
### Vector2 @ 0x11f7e90 created via move constructor
|
||||
### Vector2 @ 0x7ffef6b144b8 destroyed
|
||||
### Vector2 @ 0x11f7e90 destroyed
|
||||
v1-v2 = [-2.000000, 3.000000]
|
||||
Value constructor
|
||||
Move constructor
|
||||
Destructor.
|
||||
Destructor.
|
||||
### Vector2 @ 0x7ffef6b144c8 created [-7.000000, -6.000000]
|
||||
### Vector2 @ 0x1115760 created via move constructor
|
||||
### Vector2 @ 0x7ffef6b144c8 destroyed
|
||||
### Vector2 @ 0x1115760 destroyed
|
||||
v1-8 = [-7.000000, -6.000000]
|
||||
Value constructor
|
||||
Move constructor
|
||||
Destructor.
|
||||
Destructor.
|
||||
### Vector2 @ 0x7ffef6b144c8 created [9.000000, 10.000000]
|
||||
### Vector2 @ 0x1115760 created via move constructor
|
||||
### Vector2 @ 0x7ffef6b144c8 destroyed
|
||||
### Vector2 @ 0x1115760 destroyed
|
||||
v1+8 = [9.000000, 10.000000]
|
||||
Value constructor
|
||||
Move constructor
|
||||
Destructor.
|
||||
Destructor.
|
||||
### Vector2 @ 0x7ffef6b144b8 created [8.000000, 16.000000]
|
||||
### Vector2 @ 0x1115760 created via move constructor
|
||||
### Vector2 @ 0x7ffef6b144b8 destroyed
|
||||
### Vector2 @ 0x1115760 destroyed
|
||||
v1*8 = [8.000000, 16.000000]
|
||||
Value constructor
|
||||
Move constructor
|
||||
Destructor.
|
||||
Destructor.
|
||||
### Vector2 @ 0x7ffef6b144a8 created [0.125000, 0.250000]
|
||||
### Vector2 @ 0x112f150 created via move constructor
|
||||
### Vector2 @ 0x7ffef6b144a8 destroyed
|
||||
### Vector2 @ 0x112f150 destroyed
|
||||
v1/8 = [0.125000, 0.250000]
|
||||
Value constructor
|
||||
Move constructor
|
||||
Destructor.
|
||||
Destructor.
|
||||
### Vector2 @ 0x7ffef6b144f8 created [7.000000, 6.000000]
|
||||
### Vector2 @ 0x112f1b0 created via move constructor
|
||||
### Vector2 @ 0x7ffef6b144f8 destroyed
|
||||
### Vector2 @ 0x112f1b0 destroyed
|
||||
8-v1 = [7.000000, 6.000000]
|
||||
Value constructor
|
||||
Move constructor
|
||||
Destructor.
|
||||
Destructor.
|
||||
### Vector2 @ 0x7ffef6b144f8 created [9.000000, 10.000000]
|
||||
### Vector2 @ 0x112f1b0 created via move constructor
|
||||
### Vector2 @ 0x7ffef6b144f8 destroyed
|
||||
### Vector2 @ 0x112f1b0 destroyed
|
||||
8+v1 = [9.000000, 10.000000]
|
||||
Value constructor
|
||||
Move constructor
|
||||
Destructor.
|
||||
Destructor.
|
||||
### Vector2 @ 0x7ffef6b144e8 created [8.000000, 16.000000]
|
||||
### Vector2 @ 0x112f230 created via move constructor
|
||||
### Vector2 @ 0x7ffef6b144e8 destroyed
|
||||
### Vector2 @ 0x112f230 destroyed
|
||||
8*v1 = [8.000000, 16.000000]
|
||||
Value constructor
|
||||
Move constructor
|
||||
Destructor.
|
||||
Destructor.
|
||||
### Vector2 @ 0x7ffef6b144d8 created [8.000000, 4.000000]
|
||||
### Vector2 @ 0x11fb360 created via move constructor
|
||||
### Vector2 @ 0x7ffef6b144d8 destroyed
|
||||
### Vector2 @ 0x11fb360 destroyed
|
||||
8/v1 = [8.000000, 4.000000]
|
||||
(v1+v2)*2 = [8.000000, 2.000000]
|
||||
Destructor.
|
||||
Destructor.
|
||||
Instances not destroyed: 2
|
||||
### 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 "constructor-stats.h"
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -19,11 +20,11 @@
|
||||
class ExamplePythonTypes {
|
||||
public:
|
||||
static ExamplePythonTypes *new_instance() {
|
||||
return new ExamplePythonTypes();
|
||||
}
|
||||
~ExamplePythonTypes() {
|
||||
std::cout << "Destructing ExamplePythonTypes" << std::endl;
|
||||
auto *ptr = new ExamplePythonTypes();
|
||||
print_created(ptr, "via new_instance");
|
||||
return ptr;
|
||||
}
|
||||
~ExamplePythonTypes() { print_destroyed(this); }
|
||||
|
||||
/* Create and return a Python dictionary */
|
||||
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_static("new_instance", &ExamplePythonTypes::new_instance, "Return an instance")
|
||||
.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("__name__(example.ExamplePythonTypes.get_set) = %s" % ExamplePythonTypes.get_set.__name__)
|
||||
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
|
||||
example.ExamplePythonTypes: No constructor defined!
|
||||
can't set attribute
|
||||
### ExamplePythonTypes @ 0x1045b80 created via new_instance
|
||||
key: key2, value=value2
|
||||
key: key, value=value
|
||||
key: key, value=value
|
||||
@ -134,4 +135,6 @@ __name__(example.ExamplePythonTypes) = ExamplePythonTypes
|
||||
__module__(example.ExamplePythonTypes) = example
|
||||
__name__(example.ExamplePythonTypes.get_set) = get_set
|
||||
__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 "constructor-stats.h"
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
class Sequence {
|
||||
public:
|
||||
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];
|
||||
memset(m_data, 0, sizeof(float) * 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];
|
||||
memcpy(m_data, &value[0], sizeof(float) * 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];
|
||||
memcpy(m_data, s.m_data, sizeof(float)*m_size);
|
||||
}
|
||||
|
||||
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_data = nullptr;
|
||||
}
|
||||
|
||||
~Sequence() {
|
||||
std::cout << "Freeing a sequence with " << m_size << " entries" << std::endl;
|
||||
print_destroyed(this);
|
||||
delete[] m_data;
|
||||
}
|
||||
|
||||
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;
|
||||
m_size = s.m_size;
|
||||
m_data = new float[m_size];
|
||||
memcpy(m_data, s.m_data, sizeof(float)*m_size);
|
||||
}
|
||||
|
||||
print_copy_assigned(this);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Sequence &operator=(Sequence &&s) {
|
||||
std::cout << "Move assignment operator: Creating a sequence with " << s.m_size << " entries" << std::endl;
|
||||
if (&s != this) {
|
||||
delete[] m_data;
|
||||
m_size = s.m_size;
|
||||
@ -61,6 +65,9 @@ public:
|
||||
s.m_size = 0;
|
||||
s.m_data = nullptr;
|
||||
}
|
||||
|
||||
print_move_assigned(this);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -28,3 +28,19 @@ rev[0::2] = Sequence([2.0, 2.0, 2.0])
|
||||
for i in rev:
|
||||
print(i, end=' ')
|
||||
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
|
||||
s = <example.Sequence object at 0x10c786c70>
|
||||
### Sequence @ 0x1535b00 created of size 5
|
||||
s = <example.Sequence object at 0x7efc73cfa4e0>
|
||||
len(s) = 5
|
||||
s[0], s[3] = 0.000000 0.000000
|
||||
12.34 in s: False
|
||||
12.34 in s: True
|
||||
s[0], s[3] = 12.340000 56.779999
|
||||
Value constructor: Creating a sequence with 5 entries
|
||||
Move constructor: Creating a sequence with 5 entries
|
||||
Freeing a sequence with 0 entries
|
||||
Value constructor: Creating a sequence with 5 entries
|
||||
### Sequence @ 0x7fff22a45068 created of size 5
|
||||
### Sequence @ 0x1538b90 created via move constructor
|
||||
### Sequence @ 0x7fff22a45068 destroyed
|
||||
### 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
|
||||
0.0 56.7799987793 0.0 0.0 12.3400001526
|
||||
0.0 56.7799987793 0.0 0.0 12.3400001526
|
||||
0.0 56.779998779296875 0.0 0.0 12.34000015258789
|
||||
0.0 56.779998779296875 0.0 0.0 12.34000015258789
|
||||
True
|
||||
Value constructor: Creating a sequence with 3 entries
|
||||
Freeing a sequence with 3 entries
|
||||
2.0 56.7799987793 2.0 0.0 2.0
|
||||
Freeing a sequence with 5 entries
|
||||
Freeing a sequence with 5 entries
|
||||
Freeing a sequence with 5 entries
|
||||
### Sequence @ 0x153c4b0 created of size 3 from std::vector
|
||||
### Sequence @ 0x153c4b0 destroyed
|
||||
2.0 56.779998779296875 2.0 0.0 2.0
|
||||
Instances not destroyed: 3
|
||||
### Sequence @ 0x1535b00 destroyed
|
||||
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 {
|
||||
public:
|
||||
MyObject1(int value) : value(value) {
|
||||
std::cout << toString() << " constructor" << std::endl;
|
||||
print_created(this, toString());
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
@ -24,7 +24,7 @@ public:
|
||||
|
||||
protected:
|
||||
virtual ~MyObject1() {
|
||||
std::cout << toString() << " destructor" << std::endl;
|
||||
print_destroyed(this);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -35,7 +35,7 @@ private:
|
||||
class MyObject2 {
|
||||
public:
|
||||
MyObject2(int value) : value(value) {
|
||||
std::cout << toString() << " constructor" << std::endl;
|
||||
print_created(this, toString());
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
@ -43,7 +43,7 @@ public:
|
||||
}
|
||||
|
||||
virtual ~MyObject2() {
|
||||
std::cout << toString() << " destructor" << std::endl;
|
||||
print_destroyed(this);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -54,7 +54,7 @@ private:
|
||||
class MyObject3 : public std::enable_shared_from_this<MyObject3> {
|
||||
public:
|
||||
MyObject3(int value) : value(value) {
|
||||
std::cout << toString() << " constructor" << std::endl;
|
||||
print_created(this, toString());
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
@ -62,7 +62,7 @@ public:
|
||||
}
|
||||
|
||||
virtual ~MyObject3() {
|
||||
std::cout << toString() << " destructor" << std::endl;
|
||||
print_destroyed(this);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -144,4 +144,7 @@ void init_ex_smart_ptr(py::module &m) {
|
||||
m.def("print_myobject3_4", &print_myobject3_4);
|
||||
|
||||
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_3(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
|
||||
Initialized ref from pointer 0x1347ba0
|
||||
MyObject1[2] constructor
|
||||
Initialized ref from pointer 0x12b9270
|
||||
Initialized ref from ref 0x12b9270
|
||||
Destructing ref 0x12b9270
|
||||
MyObject1[3] constructor
|
||||
Initialized ref from pointer 0x12a2a90
|
||||
MyObject1[1]
|
||||
Created empty ref
|
||||
Assigning ref 0x1347ba0
|
||||
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
|
||||
### Object @ 0xdeffd0 created via default constructor
|
||||
### MyObject1 @ 0xdeffd0 created MyObject1[1]
|
||||
### ref<MyObject1> @ 0x7f6a2e03c4a8 created from pointer 0xdeffd0
|
||||
### Object @ 0xe43f50 created via default constructor
|
||||
### MyObject1 @ 0xe43f50 created MyObject1[2]
|
||||
### ref<Object> @ 0x7fff136845d0 created from pointer 0xe43f50
|
||||
### ref<MyObject1> @ 0x7f6a2c32aad8 created via copy constructor with pointer 0xe43f50
|
||||
### ref<Object> @ 0x7fff136845d0 destroyed
|
||||
### Object @ 0xee8cf0 created via default constructor
|
||||
### MyObject1 @ 0xee8cf0 created MyObject1[3]
|
||||
### ref<MyObject1> @ 0x7f6a2c32ab08 created from pointer 0xee8cf0
|
||||
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
|
||||
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
|
||||
<example.MyObject1 object at 0x7f830b500e68>
|
||||
<example.MyObject1 object at 0x7f830b4fc688>
|
||||
<example.MyObject1 object at 0x7f830b4fc5a8>
|
||||
MyObject1[3]
|
||||
### ref<Object> @ 0x7fff136845c8 created via default constructor
|
||||
### 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
|
||||
<example.MyObject2 object at 0x7f830b50b330>
|
||||
<example.MyObject2 object at 0x7f830b50bdb0>
|
||||
<example.MyObject2 object at 0x7f83098f6330>
|
||||
<example.MyObject3 object at 0x7f830b50b330>
|
||||
<example.MyObject3 object at 0x7f830b50bdb0>
|
||||
<example.MyObject3 object at 0x7f83098f6370>
|
||||
MyObject3[9] destructor
|
||||
### Object @ 0xee97f0 created via default constructor
|
||||
### MyObject1 @ 0xee97f0 created MyObject1[7]
|
||||
### ref<MyObject1> @ 0x7f6a2c32ab08 created from pointer 0xee97f0
|
||||
MyObject1[7]
|
||||
### 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
|
||||
### 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 "constructor-stats.h"
|
||||
#include <pybind11/functional.h>
|
||||
|
||||
/* This is an example class that we'll want to be able to extend from Python */
|
||||
class ExampleVirt {
|
||||
public:
|
||||
ExampleVirt(int state) : state(state) {
|
||||
cout << "Constructing ExampleVirt.." << endl;
|
||||
}
|
||||
|
||||
~ExampleVirt() {
|
||||
cout << "Destructing ExampleVirt.." << endl;
|
||||
}
|
||||
ExampleVirt(int state) : state(state) { print_created(this, state); }
|
||||
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); }
|
||||
|
||||
virtual int run(int value) {
|
||||
std::cout << "Original implementation of ExampleVirt::run(state=" << state
|
||||
@ -71,8 +69,8 @@ public:
|
||||
|
||||
class NonCopyable {
|
||||
public:
|
||||
NonCopyable(int a, int b) : value{new int(a*b)} {}
|
||||
NonCopyable(NonCopyable &&) = default;
|
||||
NonCopyable(int a, int b) : value{new int(a*b)} { print_created(this, a, b); }
|
||||
NonCopyable(NonCopyable &&o) { value = std::move(o.value); print_move_created(this); }
|
||||
NonCopyable(const NonCopyable &) = delete;
|
||||
NonCopyable() = delete;
|
||||
void operator=(const NonCopyable &) = delete;
|
||||
@ -80,7 +78,7 @@ public:
|
||||
std::string get_value() const {
|
||||
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:
|
||||
std::unique_ptr<int> value;
|
||||
@ -90,11 +88,11 @@ private:
|
||||
// when it is not referenced elsewhere, but copied if it is still referenced.
|
||||
class Movable {
|
||||
public:
|
||||
Movable(int a, int b) : value{a+b} {}
|
||||
Movable(const Movable &m) { value = m.value; std::cout << "Movable @ " << this << " copy constructor" << std::endl; }
|
||||
Movable(Movable &&m) { value = std::move(m.value); std::cout << "Movable @ " << this << " move constructor" << std::endl; }
|
||||
Movable(int a, int b) : value{a+b} { print_created(this, a, b); }
|
||||
Movable(const Movable &m) { value = m.value; print_copy_created(this); }
|
||||
Movable(Movable &&m) { value = std::move(m.value); print_move_created(this); }
|
||||
int get_value() const { return value; }
|
||||
~Movable() { std::cout << "Movable destructor @ " << this << "; value = " << get_value() << std::endl; }
|
||||
~Movable() { print_destroyed(this); }
|
||||
private:
|
||||
int value;
|
||||
};
|
||||
@ -305,5 +303,6 @@ void init_ex_virtual_functions(py::module &m) {
|
||||
m.def("runExampleVirtBool", &runExampleVirtBool);
|
||||
m.def("runExampleVirtVirtual", &runExampleVirtVirtual);
|
||||
|
||||
m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
|
||||
initialize_inherited_virtuals(m);
|
||||
}
|
||||
|
@ -37,8 +37,6 @@ print(runExampleVirt(ex12p, 20))
|
||||
print(runExampleVirtBool(ex12p))
|
||||
runExampleVirtVirtual(ex12p)
|
||||
|
||||
sys.stdout.flush()
|
||||
|
||||
class VI_AR(A_Repeat):
|
||||
def unlucky_number(self):
|
||||
return 99
|
||||
@ -122,3 +120,16 @@ try:
|
||||
except RuntimeError as e:
|
||||
# Don't print the exception message here because it differs under debug/non-debug mode
|
||||
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)
|
||||
30
|
||||
Caught expected exception: Tried to call pure virtual function "ExampleVirt::pure_virtual"
|
||||
Constructing ExampleVirt..
|
||||
### ExampleVirt @ 0x2076a00 created 11
|
||||
ExtendedExampleVirt::run(20), calling parent..
|
||||
Original implementation of ExampleVirt::run(state=11, value=21)
|
||||
32
|
||||
@ -78,20 +78,29 @@ VI_DT says: quack quack quack
|
||||
Unlucky = 1234
|
||||
Lucky = -4.25
|
||||
2^2 * 3^2 =
|
||||
NonCopyable destructor @ 0x1a6c3f0; value = (null)
|
||||
### NonCopyable @ 0x207df10 created 4 9
|
||||
### NonCopyable @ 0x7ffcfe866228 created via move constructor
|
||||
### NonCopyable @ 0x207df10 destroyed
|
||||
36
|
||||
NonCopyable destructor @ 0x7ffc6d1fbaa8; value = 36
|
||||
### NonCopyable @ 0x7ffcfe866228 destroyed
|
||||
4 + 5 =
|
||||
Movable @ 0x7ffc6d1fbacc copy constructor
|
||||
### Movable @ 0x207e230 created 4 5
|
||||
### Movable @ 0x7ffcfe86624c created via copy constructor
|
||||
9
|
||||
Movable destructor @ 0x7ffc6d1fbacc; value = 9
|
||||
### Movable @ 0x7ffcfe86624c destroyed
|
||||
7 + 7 =
|
||||
Movable @ 0x7ffc6d1fbacc move constructor
|
||||
Movable destructor @ 0x1a6c4d0; value = 14
|
||||
### Movable @ 0x20259e0 created 7 7
|
||||
### Movable @ 0x7ffcfe86624c created via move constructor
|
||||
### Movable @ 0x20259e0 destroyed
|
||||
14
|
||||
Movable destructor @ 0x7ffc6d1fbacc; value = 14
|
||||
### Movable @ 0x7ffcfe86624c destroyed
|
||||
### NonCopyable @ 0x2025a00 created 9 9
|
||||
Caught expected exception
|
||||
NonCopyable destructor @ 0x29a64b0; value = 81
|
||||
Movable destructor @ 0x1a6c410; value = 9
|
||||
Destructing ExampleVirt..
|
||||
Destructing ExampleVirt..
|
||||
### ExampleVirt @ 0x2073a90 destroyed
|
||||
### ExampleVirt @ 0x2076a00 destroyed
|
||||
### Movable @ 0x207e230 destroyed
|
||||
### 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 "constructor-stats.h"
|
||||
|
||||
void init_ex_methods_and_attributes(py::module &);
|
||||
void init_ex_python_types(py::module &);
|
||||
@ -34,9 +35,24 @@ void init_issues(py::module &);
|
||||
void init_eigen(py::module &);
|
||||
#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) {
|
||||
py::module m("example", "pybind example plugin");
|
||||
|
||||
bind_ConstructorStats(m);
|
||||
|
||||
init_ex_methods_and_attributes(m);
|
||||
init_ex_python_types(m);
|
||||
init_ex_operator_overloading(m);
|
||||
|
@ -8,11 +8,18 @@
|
||||
*/
|
||||
|
||||
#include "example.h"
|
||||
#include "constructor-stats.h"
|
||||
#include <pybind11/stl.h>
|
||||
#include <pybind11/operators.h>
|
||||
|
||||
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) {
|
||||
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
|
||||
#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_<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);
|
||||
|
@ -24,15 +24,15 @@ Failed as expected: Incompatible constructor arguments. The following argument t
|
||||
1. example.issues.StrIssue(arg0: int)
|
||||
2. example.issues.StrIssue()
|
||||
Invoked with: no, such, constructor
|
||||
NestABase@0x1152940 constructor
|
||||
NestA@0x1152940 constructor
|
||||
NestABase@0x11f9350 constructor
|
||||
NestA@0x11f9350 constructor
|
||||
NestB@0x11f9350 constructor
|
||||
NestABase@0x112d0d0 constructor
|
||||
NestA@0x112d0d0 constructor
|
||||
NestB@0x112d0d0 constructor
|
||||
NestC@0x112d0d0 constructor
|
||||
### NestABase @ 0x15eb630 created via default constructor
|
||||
### NestA @ 0x15eb630 created via default constructor
|
||||
### NestABase @ 0x1704000 created via default constructor
|
||||
### NestA @ 0x1704000 created via default constructor
|
||||
### NestB @ 0x1704000 created via default constructor
|
||||
### NestABase @ 0x1633110 created via default constructor
|
||||
### NestA @ 0x1633110 created via default constructor
|
||||
### NestB @ 0x1633110 created via default constructor
|
||||
### NestC @ 0x1633110 created via default constructor
|
||||
13
|
||||
103
|
||||
1003
|
||||
@ -43,13 +43,13 @@ NestC@0x112d0d0 constructor
|
||||
42
|
||||
-2
|
||||
42
|
||||
NestC@0x112d0d0 destructor
|
||||
NestB@0x112d0d0 destructor
|
||||
NestA@0x112d0d0 destructor
|
||||
NestABase@0x112d0d0 destructor
|
||||
### NestC @ 0x1633110 destroyed
|
||||
### NestB @ 0x1633110 destroyed
|
||||
### NestA @ 0x1633110 destroyed
|
||||
### NestABase @ 0x1633110 destroyed
|
||||
42
|
||||
NestA@0x1152940 destructor
|
||||
NestABase@0x1152940 destructor
|
||||
NestB@0x11f9350 destructor
|
||||
NestA@0x11f9350 destructor
|
||||
NestABase@0x11f9350 destructor
|
||||
### NestA @ 0x15eb630 destroyed
|
||||
### NestABase @ 0x15eb630 destroyed
|
||||
### NestB @ 0x1704000 destroyed
|
||||
### NestA @ 0x1704000 destroyed
|
||||
### NestABase @ 0x1704000 destroyed
|
||||
|
@ -2,15 +2,16 @@
|
||||
#define __OBJECT_H
|
||||
|
||||
#include <atomic>
|
||||
#include "constructor-stats.h"
|
||||
|
||||
/// Reference counted object base class
|
||||
class Object {
|
||||
public:
|
||||
/// Default constructor
|
||||
Object() { }
|
||||
Object() { print_default_created(this); }
|
||||
|
||||
/// Copy constructor
|
||||
Object(const Object &) : m_refCount(0) {}
|
||||
Object(const Object &) : m_refCount(0) { print_copy_created(this); }
|
||||
|
||||
/// Return the current reference count
|
||||
int getRefCount() const { return m_refCount; };
|
||||
@ -37,11 +38,17 @@ protected:
|
||||
/** \brief Virtual protected deconstructor.
|
||||
* (Will only be called by \ref ref)
|
||||
*/
|
||||
virtual ~Object() { }
|
||||
virtual ~Object() { print_destroyed(this); }
|
||||
private:
|
||||
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
|
||||
*
|
||||
@ -55,37 +62,43 @@ private:
|
||||
template <typename T> class ref {
|
||||
public:
|
||||
/// 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
|
||||
ref(T *ptr) : m_ptr(ptr) {
|
||||
std::cout << "Initialized ref from pointer " << ptr<< std::endl;
|
||||
if (m_ptr) ((Object *) m_ptr)->incRef();
|
||||
|
||||
print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer");
|
||||
|
||||
}
|
||||
|
||||
/// Copy constructor
|
||||
ref(const ref &r) : m_ptr(r.m_ptr) {
|
||||
std::cout << "Initialized ref from ref " << r.m_ptr << std::endl;
|
||||
if (m_ptr)
|
||||
((Object *) m_ptr)->incRef();
|
||||
|
||||
print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this);
|
||||
}
|
||||
|
||||
/// Move constructor
|
||||
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;
|
||||
|
||||
print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
|
||||
}
|
||||
|
||||
/// Destroy this reference
|
||||
~ref() {
|
||||
std::cout << "Destructing ref " << m_ptr << std::endl;
|
||||
if (m_ptr)
|
||||
((Object *) m_ptr)->decRef();
|
||||
|
||||
print_destroyed(this); track_destroyed((ref_tag*) this);
|
||||
}
|
||||
|
||||
/// Move another reference into the current one
|
||||
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)
|
||||
return *this;
|
||||
if (m_ptr)
|
||||
@ -97,7 +110,8 @@ public:
|
||||
|
||||
/// Overwrite this reference with another reference
|
||||
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)
|
||||
return *this;
|
||||
if (m_ptr)
|
||||
@ -110,7 +124,8 @@ public:
|
||||
|
||||
/// Overwrite this reference with a pointer to another object
|
||||
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)
|
||||
return *this;
|
||||
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]+')
|
||||
shorten_floats = re.compile(r'([1-9][0-9]*\.[0-9]{4})[0-9]*')
|
||||
|
||||
relaxed = False
|
||||
|
||||
def sanitize(lines):
|
||||
lines = lines.split('\n')
|
||||
for i in range(len(lines)):
|
||||
line = lines[i]
|
||||
if line.startswith(" |"):
|
||||
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_long_marker.sub(r'\1', line)
|
||||
line = remove_hex.sub(r'0', line)
|
||||
@ -28,13 +30,6 @@ def sanitize(lines):
|
||||
line = line.replace('example.EMode', 'EMode')
|
||||
line = line.replace('method of builtins.PyCapsule instance', '')
|
||||
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
|
||||
|
||||
return '\n'.join(sorted([l for l in lines if l != ""]))
|
||||
@ -44,16 +39,12 @@ if path != '':
|
||||
os.chdir(path)
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Syntax: %s [--relaxed] <test name>" % sys.argv[0])
|
||||
print("Syntax: %s <test name>" % sys.argv[0])
|
||||
exit(0)
|
||||
|
||||
if len(sys.argv) == 3 and sys.argv[1] == '--relaxed':
|
||||
del sys.argv[1]
|
||||
relaxed = True
|
||||
|
||||
name = sys.argv[1]
|
||||
try:
|
||||
output_bytes = subprocess.check_output([sys.executable, name + ".py"],
|
||||
output_bytes = subprocess.check_output([sys.executable, "-u", name + ".py"],
|
||||
stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
if e.returncode == 99:
|
||||
|
Loading…
Reference in New Issue
Block a user