ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Пятница
19 июля
1352412
VVB (19.09.2023 10:02, просмотров: 1670)
Про 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

Что я не понимаю?