Boost :: make_shared doesn't call (place) the new operator?

I use boost :: make_shared to create objects that are shared by pointers. Mainly because our code was too slow, and one distribution really helped improve performance.

After fixing the memory leaks, the “hard manual way”, I decided to implement a simple memory leak detector, redefining the new operators for all the corresponding classes only to count which objects are still alive at certain points in our application. I implemented this several times earlier and was surprised to find that my code no longer detects any objects.

I realized that all I had to do was to redefine the "placement of new" instead of the "normal" new operator due to the following from the boost website documentation for make_shared:

"Effects: allocates memory suitable for an object of type T and creates an object in it through a new expression new (pv) T () or new (pv) T (std :: forward (args) ...) . Allocate_shared uses a copy of a for memory allocation. If an exception is thrown, the effect. "

My new placement is also not called. I wrote a small test program to reproduce the behavior:

#include <iostream> using namespace std; #include "boost/shared_ptr.hpp" #include "boost/make_shared.hpp" class Test { public: Test() { cout << "Test::Test()" << endl; } void* operator new (std::size_t size) throw (std::bad_alloc) { cout << "Test new" << endl; return malloc(size); } void* operator new (std::size_t size, const std::nothrow_t& nothrow_constant) throw() { cout << "Test non-throwing new" << endl; return malloc(size); } void* operator new (std::size_t size, void* ptr) throw() { cout << "Test non-throwing placement new" << endl; return malloc(size); } }; void* operator new (std::size_t size) throw (std::bad_alloc) { cout << "Global new" << endl; return malloc(size); } int main() { cout << "..." << endl; boost::shared_ptr<Test> t1(boost::make_shared<Test>()); cout << "..." << endl; boost::shared_ptr<Test> t2(new Test()); cout << "..." << endl; return 0; } 

Which makes the following conclusion:

 ... Global new Test::Test() ... Test new Test::Test() Global new ... 

I was expecting "Test non-throwing placement new" on the third line of output. What do you think should be the behavior? Do you agree that, according to the documentation of make_shared, it should name the new placement operator of my class Test? Or didn’t I understand this?

I could copy the implementation implementation locally and, of course, add a call to the new placement operator. But would this be appropriate or would violate the alleged semantics of placing new?

Thanks in advance for your time and your help.

+6
source share
3 answers

As a make_shared source make_shared it uses the new global operator of placement instead of the new operator provided by your class.

 ::new( pv ) T(); 

Unfortunately (at least on OS X) ( according to the standard ), you cannot define your own new global allocation operator. It appears that allocate_shared more consistent with what you are looking for.

Edit

An alternative could actually be to write a version of make_shared that uses the new class placement instead of the global one. These are just about 10 lines of code, and should be fine if you read the source code license .

+8
source

You cannot replace a new placement (§18.4. 1.3, see, for example, this question ), so the output seems fine.

As an alternative to changing Boost headers, you can look at external tools like Valgrind.

+4
source

Your operator new , implemented for your specific type, will be used only in expressions to which elements of your type are dynamically allocated using new , for example Test *p = new Test; . Now make_shared does not dynamically allocate an object of your type, but rather a buffer that contains enough information for a general count (which includes a counter, deletion, and a few extra bits and parts) and your object.

Then it uses place-new to call the constructor of your object. Note that placing a new one in this case does not allocate memory, only the funny syntax in C ++ calls the constructor on a block of already allocated memory. In fact, this can be a source of confusion, because the expression new , your operator new and place-new are three different concepts that share a name.

+3
source

Source: https://habr.com/ru/post/910543/


All Articles