Я впервые использую boost::make_shared для создания объектов, на которые указывают общие указатели. Главным образом потому, что наш код был слишком медленным, а однократное выделение действительно помогло повысить производительность.
После исправления некоторых утечек памяти «жестким ручным способом» я решил реализовать простой детектор утечек памяти, переопределив новые операторы для всех соответствующих классов только для подсчета того, какие объекты все еще живы в определенных точках нашего приложения. Я реализовал это несколько раз раньше и был удивлен, обнаружив, что мой код больше не обнаруживает никаких объектов.
Я решил, что все, что мне нужно было сделать, это переопределить «размещение нового» вместо «обычного» оператора new из-за следующего из документации веб-сайта boost для make_shared:
«Эффекты: Выделяет память, подходящую для объекта типа T , и создает в ней объект с помощью выражения new(pv) T() или new(pv) T(std::forward(args)). ... ). allocate_shared использует копию a для выделения памяти. Если возникает исключение, не имеет никакого эффекта."
Однако мое новое размещение также не называется. Я написал небольшую тестовую программу для воспроизведения поведения:
#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;
}
Что выводит следующий вывод:
...
Global new
Test::Test()
...
Test new
Test::Test()
Global new
...
Я ожидал, что «Тестовое новое размещение без броска» в 3-й строке вывода. Как вы думаете, каким должно быть поведение? Согласны ли вы с тем, что в соответствии с документацией make_shared он должен вызывать новый оператор размещения моего тестового класса? Или я неправильно понял?
Я мог бы скопировать реализацию бустов локально и, конечно, добавить вызов нового оператора размещения. Но будет ли это уместно или нарушит предполагаемую семантику размещения new?
Заранее спасибо за ваше время и вашу помощь.