Про std::shared_ptr, std::make_shared, std::queue можете
подсказать? Я организую передачу данных от одного потока к другому с помощью очереди, и кое-что не понимаю. Для упрощения убрал мьютексы для доступа к критическим данным.
Вот код #1
#include <iostream>
#include <memory>
#include <queue>
class Test
{
public:
Test(int i) : i{i} {std::cout << "Construct #" << i << "\n";}
~Test() {std::cout << "Destruct #" << i << "\n";}
Test& operator=(const Test& t){std::cout << "Copy assignment\n"; return const_cast<Test&>(t);}
Test(const Test&) {std::cout << "Copy constructor\n";}
int i;
};
std::queue<std::shared_ptr<Test>> q;
std::shared_ptr<class Test> makeTest(const int i)
{
auto msg = std::make_shared<class Test>(i);
return msg;
}
void receive(const std::shared_ptr<class Test>& t)
{
std::cout << "receive: use_count=" << t.use_count() << std::endl;
q.push(t);
}
const std::shared_ptr<class Test>& getLast()
{
const std::shared_ptr<class Test>& rc = q.front();
std::cout << "getLast1: use_count=" << rc.use_count() << std::endl;
q.pop();
std::cout << "getLast2: use_count=" << rc.use_count() << std::endl;
return rc;
}
bool isTestInQueue()
{
const bool rc = q.empty();
return !rc;
}
void printTest(const class Test& t)
{
std::cout << "Print test #" << t.i << std::endl;
}
void process()
{
while (isTestInQueue())
{
const auto t = getLast();
std::cout << "process: use_count=" << t.use_count() << std::endl;
printTest(*t);
}
}
void writeTest()
{
const auto t = makeTest(0);
std::cout << "writeTest: use_count=" << t.use_count() << std::endl;
receive(t);
}
int main()
{
std::cout << "start" << std::endl;
writeTest();
std::cout << "process" << std::endl;
process();
std::cout << "end" << std::endl;
return 0;
}
Вывод:
start
Construct #0
writeTest: use_count=1
receive: use_count=1
process
getLast1: use_count=1
Destruct #0
getLast2: use_count=26861584
process: use_count=26861585
Print test #0
end
На мой взгляд, код должен работать нормально. Но он не работает: в строке вывода "getLast2" и в функции process() блок памяти уже освобождён, вызывается деструктор объекта до отладочной печати. Хотя полученный из очереди объект ещё не вышел из области видимости.
Проверял тут https://www.programiz.com/cpp-programming/online-compiler/
Вот такой код #2 работает, но имеется лишняя и ненужная мне операция увеличения счётчика shared_ptr; деструктор вызывается после выхода из функции printTest().
#include <iostream>
#include <memory>
#include <queue>
class Test
{
public:
Test(int i) : i{i} {std::cout << "Construct #" << i << "\n";}
~Test() {std::cout << "Destruct #" << i << "\n";}
Test& operator=(const Test& t){std::cout << "Copy assignment\n"; return const_cast<Test&>(t);}
Test(const Test&) {std::cout << "Copy constructor\n";}
int i;
};
std::queue<std::shared_ptr<Test>> q;
std::shared_ptr<class Test> makeTest(const int i)
{
auto msg = std::make_shared<class Test>(i);
return msg;
}
void receive(const std::shared_ptr<class Test>& t)
{
std::cout << "receive: use_count=" << t.use_count() << std::endl;
q.push(t);
}
const std::shared_ptr<class Test> getLast()
{
const std::shared_ptr<class Test> rc = q.front();
std::cout << "getLast1: use_count=" << rc.use_count() << std::endl;
q.pop();
std::cout << "getLast2: use_count=" << rc.use_count() << std::endl;
return rc;
}
bool isTestInQueue()
{
const bool rc = q.empty();
return !rc;
}
void printTest(const class Test& t)
{
std::cout << "Print test #" << t.i << std::endl;
}
void process()
{
while (isTestInQueue())
{
const auto t = getLast();
std::cout << "process: use_count=" << t.use_count() << std::endl;
printTest(*t);
}
}
void writeTest()
{
const auto t = makeTest(0);
std::cout << "writeTest: use_count=" << t.use_count() << std::endl;
receive(t);
}
int main()
{
std::cout << "start" << std::endl;
writeTest();
std::cout << "process" << std::endl;
process();
std::cout << "end" << std::endl;
return 0;
}
Вывод:
start
Construct #0
writeTest: use_count=1
receive: use_count=1
process
getLast1: use_count=2
getLast2: use_count=1
process: use_count=1
Print test #0
Destruct #0
end
Что я не понимаю?