Commit f4f2afb6 authored by Wenzel Jakob's avatar Wenzel Jakob Committed by GitHub
Browse files

Merge pull request #324 from jagerman/example-constructor-tracking

Improve constructor/destructor tracking
parents 85557b1d 3f589379
...@@ -65,3 +65,10 @@ print("__name__(example.ExamplePythonTypes) = %s" % ExamplePythonTypes.__name__) ...@@ -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 @@ ...@@ -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 ...@@ -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 @@ ...@@ -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: ...@@ -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]) ...@@ -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)
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 @@ ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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) { ...@@ -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()]: ...@@ -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])
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
### Object @ 0xee8cf0 created via default constructor
### MyObject1 @ 0xee8cf0 created MyObject1[3]
### ref<MyObject1> @ 0x7f6a2c32ab08 created from pointer 0xee8cf0
Reference count = 1
MyObject1[1] MyObject1[1]
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1347ba0 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xdeffd0
Initialized ref from ref 0x1347ba0 ### ref<Object> @ 0x7fff136845a8 created via copy constructor with pointer 0xdeffd0
MyObject1[1] MyObject1[1]
Destructing ref 0x1347ba0 ### ref<Object> @ 0x7fff136845a8 destroyed
Destructing ref 0x1347ba0 ### ref<Object> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1347ba0 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xdeffd0
MyObject1[1] MyObject1[1]
Destructing ref 0x1347ba0 ### ref<Object> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1347ba0 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xdeffd0
MyObject1[1] MyObject1[1]
Destructing ref 0x1347ba0 ### ref<Object> @ 0x7fff136845c8 destroyed
Reference count = 1
MyObject1[2] MyObject1[2]
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x12b9270 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xe43f50
Initialized ref from ref 0x12b9270 ### ref<Object> @ 0x7fff136845a8 created via copy constructor with pointer 0xe43f50
MyObject1[2] MyObject1[2]
Destructing ref 0x12b9270 ### ref<Object> @ 0x7fff136845a8 destroyed
Destructing ref 0x12b9270 ### ref<Object> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x12b9270 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xe43f50
MyObject1[2] MyObject1[2]
Destructing ref 0x12b9270 ### ref<Object> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x12b9270 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xe43f50
MyObject1[2] MyObject1[2]
Destructing ref 0x12b9270 ### ref<Object> @ 0x7fff136845c8 destroyed
Reference count = 1
MyObject1[3] MyObject1[3]
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x12a2a90 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8cf0
Initialized ref from ref 0x12a2a90 ### ref<Object> @ 0x7fff136845a8 created via copy constructor with pointer 0xee8cf0
MyObject1[3] MyObject1[3]
Destructing ref 0x12a2a90 ### ref<Object> @ 0x7fff136845a8 destroyed
Destructing ref 0x12a2a90 ### ref<Object> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x12a2a90 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8cf0
MyObject1[3] MyObject1[3]
Destructing ref 0x12a2a90 ### ref<Object> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x12a2a90 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8cf0
MyObject1[3] MyObject1[3]
Destructing ref 0x12a2a90 ### ref<Object> @ 0x7fff136845c8 destroyed
Destructing ref 0x12b9270 ### MyObject1 @ 0xe43f50 destroyed
MyObject1[2] destructor ### Object @ 0xe43f50 destroyed
Destructing ref 0x1347ba0 ### ref<MyObject1> @ 0x7f6a2c32aad8 destroyed
MyObject1[1] destructor ### MyObject1 @ 0xdeffd0 destroyed
MyObject1[4] constructor ### Object @ 0xdeffd0 destroyed
Initialized ref from pointer 0x1347ba0 ### ref<MyObject1> @ 0x7f6a2e03c4a8 destroyed
MyObject1[5] constructor ### Object @ 0xee8310 created via default constructor
Initialized ref from pointer 0x1299190 ### MyObject1 @ 0xee8310 created MyObject1[4]
Initialized ref from ref 0x1299190 ### ref<MyObject1> @ 0x7f6a2e03c4a8 created from pointer 0xee8310
Destructing ref 0x1299190 ### Object @ 0xee8470 created via default constructor
MyObject1[6] constructor ### MyObject1 @ 0xee8470 created MyObject1[5]
Initialized ref from pointer 0x133e2f0 ### ref<MyObject1> @ 0x7fff136845d0 created from pointer 0xee8470
Destructing ref 0x12a2a90 ### ref<MyObject1> @ 0x7f6a2c32aad8 created via copy constructor with pointer 0xee8470
MyObject1[3] destructor ### 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] MyObject1[4]
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1347ba0 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310
Initialized ref from ref 0x1347ba0 ### ref<Object> @ 0x7fff136845a8 created via copy constructor with pointer 0xee8310
MyObject1[4] MyObject1[4]
Destructing ref 0x1347ba0 ### ref<Object> @ 0x7fff136845a8 destroyed
Destructing ref 0x1347ba0 ### ref<Object> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1347ba0 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310
MyObject1[4] MyObject1[4]
Destructing ref 0x1347ba0 ### ref<Object> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1347ba0 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310
MyObject1[4] MyObject1[4]
Destructing ref 0x1347ba0 ### ref<Object> @ 0x7fff136845c8 destroyed
MyObject1[4] MyObject1[4]
Created empty ref ### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1347ba0 ### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310
Initialized ref from ref 0x1347ba0 ### ref<MyObject1> @ 0x7fff136845a8 created via copy constructor with pointer 0xee8310
MyObject1[4] MyObject1[4]
Destructing ref 0x1347ba0 ### ref<MyObject1> @ 0x7fff136845a8 destroyed
Destructing ref 0x1347ba0 ### ref<MyObject1> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1347ba0 ### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310
MyObject1[4] MyObject1[4]
Destructing ref 0x1347ba0 ### ref<MyObject1> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1347ba0 ### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310
MyObject1[4] MyObject1[4]
Destructing ref 0x1347ba0 ### ref<MyObject1> @ 0x7fff136845c8 destroyed
<example.MyObject1 object at 0x7f6a2c32aab0>
MyObject1[5] MyObject1[5]
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1299190 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470
Initialized ref from ref 0x1299190 ### ref<Object> @ 0x7fff136845a8 created via copy constructor with pointer 0xee8470
MyObject1[5] MyObject1[5]
Destructing ref 0x1299190 ### ref<Object> @ 0x7fff136845a8 destroyed
Destructing ref 0x1299190 ### ref<Object> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1299190 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470
MyObject1[5] MyObject1[5]
Destructing ref 0x1299190 ### ref<Object> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1299190 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470
MyObject1[5] MyObject1[5]
Destructing ref 0x1299190 ### ref<Object> @ 0x7fff136845c8 destroyed
MyObject1[5] MyObject1[5]
Created empty ref ### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1299190 ### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470
Initialized ref from ref 0x1299190 ### ref<MyObject1> @ 0x7fff136845a8 created via copy constructor with pointer 0xee8470
MyObject1[5] MyObject1[5]
Destructing ref 0x1299190 ### ref<MyObject1> @ 0x7fff136845a8 destroyed
Destructing ref 0x1299190 ### ref<MyObject1> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1299190 ### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470
MyObject1[5] MyObject1[5]
Destructing ref 0x1299190 ### ref<MyObject1> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x1299190 ### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470
MyObject1[5] MyObject1[5]
Destructing ref 0x1299190 ### ref<MyObject1> @ 0x7fff136845c8 destroyed
<example.MyObject1 object at 0x7f6a2c32ab10>
MyObject1[6] MyObject1[6]
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x133e2f0 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0
Initialized ref from ref 0x133e2f0 ### ref<Object> @ 0x7fff136845a8 created via copy constructor with pointer 0xee95a0
MyObject1[6] MyObject1[6]
Destructing ref 0x133e2f0 ### ref<Object> @ 0x7fff136845a8 destroyed
Destructing ref 0x133e2f0 ### ref<Object> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x133e2f0 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0
MyObject1[6] MyObject1[6]
Destructing ref 0x133e2f0 ### ref<Object> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<Object> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x133e2f0 ### ref<Object> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0
MyObject1[6] MyObject1[6]
Destructing ref 0x133e2f0 ### ref<Object> @ 0x7fff136845c8 destroyed
MyObject1[6] MyObject1[6]
Created empty ref ### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x133e2f0 ### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0
Initialized ref from ref 0x133e2f0 ### ref<MyObject1> @ 0x7fff136845a8 created via copy constructor with pointer 0xee95a0
MyObject1[6] MyObject1[6]
Destructing ref 0x133e2f0 ### ref<MyObject1> @ 0x7fff136845a8 destroyed
Destructing ref 0x133e2f0 ### ref<MyObject1> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x133e2f0 ### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0
MyObject1[6] MyObject1[6]
Destructing ref 0x133e2f0 ### ref<MyObject1> @ 0x7fff136845c8 destroyed
Created empty ref ### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
Assigning ref 0x133e2f0 ### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0
MyObject1[6] MyObject1[6]
Destructing ref 0x133e2f0 ### ref<MyObject1> @ 0x7fff136845c8 destroyed
MyObject1[7] constructor 7
Initialized ref from pointer 0x133f3a0 ### Object @ 0xee97f0 created via default constructor
### MyObject1 @ 0xee97f0 created MyObject1[7]
### ref<MyObject1> @ 0x7f6a2c32ab08 created from pointer 0xee97f0
MyObject1[7] MyObject1[7]
Destructing ref 0x133f3a0 ### MyObject1 @ 0xee97f0 destroyed
MyObject1[7] destructor ### Object @ 0xee97f0 destroyed
Created empty ref ### ref<MyObject1> @ 0x7f6a2c32ab08 destroyed
MyObject1[7] constructor ### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
Initialized ref from pointer 0x12a2a90 ### Object @ 0xee99e0 created via default constructor
Assigning ref 0x12a2a90 ### MyObject1 @ 0xee99e0 created MyObject1[7]
Initialized ref from ref 0x12a2a90 ### 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] MyObject1[7]
Destructing ref 0x12a2a90 ### ref<MyObject1> @ 0x7fff136845a8 destroyed
Destructing ref 0x12a2a90 ### ref<MyObject1> @ 0x7fff136845c8 destroyed
Destructing ref 0x12a2a90 ### MyObject1 @ 0xee99e0 destroyed
MyObject1[7] destructor ### Object @ 0xee99e0 destroyed
Created empty ref ### ref<MyObject1> @ 0x7f6a2c32ab08 destroyed
MyObject1[7] constructor ### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
Initialized ref from pointer 0x133f3a0 ### Object @ 0xee97f0 created via default constructor
Assigning ref 0x133f3a0 ### MyObject1 @ 0xee97f0 created MyObject1[7]
### ref<MyObject1> @ 0x7f6a2c32ab08 created from pointer 0xee97f0
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee97f0
MyObject1[7] MyObject1[7]
Destructing ref 0x133f3a0 ### ref<MyObject1> @ 0x7fff136845c8 destroyed
Destructing ref 0x133f3a0 ### MyObject1 @ 0xee97f0 destroyed
MyObject1[7] destructor ### Object @ 0xee97f0 destroyed
Created empty ref ### ref<MyObject1> @ 0x7f6a2c32ab08 destroyed
MyObject1[7] constructor ### ref<MyObject1> @ 0x7fff136845c8 created via default constructor
Initialized ref from pointer 0x12a2a90 ### Object @ 0xee99e0 created via default constructor
Assigning ref 0x12a2a90 ### MyObject1 @ 0xee99e0 created MyObject1[7]
### ref<MyObject1> @ 0x7f6a2c32ab08 created from pointer 0xee99e0
### ref<MyObject1> @ 0x7fff136845c8 assigned via copy assignment pointer 0xee99e0
MyObject1[7] MyObject1[7]
Destructing ref 0x12a2a90 ### ref<MyObject1> @ 0x7fff136845c8 destroyed
Destructing ref 0x12a2a90 ### MyObject1 @ 0xee99e0 destroyed
MyObject1[7] destructor ### Object @ 0xee99e0 destroyed
Destructing ref 0x133e2f0 ### ref<MyObject1> @ 0x7f6a2c32ab08 destroyed
MyObject1[6] destructor ### MyObject1 @ 0xee95a0 destroyed
Destructing ref 0x1299190 ### Object @ 0xee95a0 destroyed
MyObject1[5] destructor ### ref<MyObject1> @ 0x7f6a2c32ab38 destroyed
Destructing ref 0x1347ba0 ### MyObject1 @ 0xee8470 destroyed
MyObject1[4] destructor ### Object @ 0xee8470 destroyed
MyObject2[8] constructor ### ref<MyObject1> @ 0x7f6a2c32aad8 destroyed
MyObject2[6] constructor ### MyObject1 @ 0xee8310 destroyed
MyObject2[7] constructor ### 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]
MyObject2[8] MyObject2[8]
MyObject2[8] MyObject2[8]
<example.MyObject2 object at 0x7f6a2dfc86c0>
MyObject2[6] MyObject2[6]
MyObject2[6] MyObject2[6]
MyObject2[6] MyObject2[6]
MyObject2[6] MyObject2[6]
<example.MyObject2 object at 0x7f6a2c32d030>
MyObject2[7] MyObject2[7]
MyObject2[7] MyObject2[7]
MyObject2[7] MyObject2[7]
MyObject2[7] MyObject2[7]
MyObject2[6] destructor ### MyObject2 @ 0xee95a0 destroyed
MyObject2[8] destructor ### MyObject2 @ 0xe43f50 destroyed
MyObject3[9] constructor ### MyObject3 @ 0xee9ac0 created MyObject3[9]
MyObject3[8] constructor ### MyObject3 @ 0xe43f90 created MyObject3[8]
MyObject3[9] constructor ### MyObject3 @ 0xeea7d0 created MyObject3[9]
MyObject2[7] destructor ### MyObject2 @ 0xee95d0 destroyed
<example.MyObject3 object at 0x7f6a2dfc8768>
MyObject3[9] MyObject3[9]
MyObject3[9] MyObject3[9]
MyObject3[9] MyObject3[9]
MyObject3[9] MyObject3[9]
<example.MyObject3 object at 0x7f6a2dfc86c0>
MyObject3[8] MyObject3[8]
MyObject3[8] MyObject3[8]
MyObject3[8] MyObject3[8]
MyObject3[8] MyObject3[8]
<example.MyObject3 object at 0x7f6a2c32d068>
MyObject3[9] MyObject3[9]
MyObject3[9] MyObject3[9]
MyObject3[9] MyObject3[9]
MyObject3[9] MyObject3[9]
MyObject3[8] destructor ### MyObject3 @ 0xe43f90 destroyed
MyObject3[9] destructor ### MyObject3 @ 0xee9ac0 destroyed
Reference count = 1 Instances not destroyed: [0, 0, 0, 1, 0]
Reference count = 1 ### MyObject3 @ 0xeea7d0 destroyed
Reference count = 1 Instances not destroyed: [0, 0, 0, 0, 0]
<example.MyObject1 object at 0x7f830b500e68> 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']]
<example.MyObject1 object at 0x7f830b4fc688> Default constructions: [10, 0, 0, 0, 30]
<example.MyObject1 object at 0x7f830b4fc5a8> Copy constructions: [0, 0, 0, 0, 12]
7 Copy assignments: [0, 0, 0, 0, 30]
<example.MyObject2 object at 0x7f830b50b330> Move assignments: [0, 0, 0, 0, 0]
<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
...@@ -8,18 +8,16 @@ ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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) { ...@@ -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)) ...@@ -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: ...@@ -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))])
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 ...@@ -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 @@ ...@@ -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 &); ...@@ -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 @@ ...@@ -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) { ...@@ -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 ...@@ -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 ...@@ -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 @@ ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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') ...@@ -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): ...@@ -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 != '': ...@@ -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:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment