область действия — C ++: непонимание правил уничтожения объектов

Следующий фрагмент кода C ++ использует Microsoft C ++ Rest SDK. Я не понимаю, почему первый фрагмент работает, а другой нет. Я предполагаю, что различия связаны с разрушением объекта и правилами определения области видимости. Я ищу объяснение того, почему первый фрагмент работает, а другие фрагменты зависают при закрытии (). Кроме того, что может сделать SDK для устранения ошибок в будущем. Некоторые действительно умные люди смотрели на фрагмент, но никогда не видели проблему.

Первый фрагмент кода. Этот фрагмент работает и показан в полном объеме. Последующие фрагменты кода заменяют помеченный код внутри. Пожалуйста, сосредоточьтесь на различиях, а не на других отвлекающих моментах. Код был протестирован путем выполнения одного запроса GET в браузере и пошагового выполнения кода. Во всех случаях request.reply () выполнялся один раз и только один раз.

    boost::lockfree::spsc_queue<web::http::http_request, boost::lockfree::capacity<1024>> queue;
web::http::experimental::listener::http_listener listener(U("http://localhost:3901"));
listener.support([&](web::http::http_request request)
{
queue.push(request);
});
listener.open().wait();
std::cout << "listening ... hit enter to initiate shutdown." << std::endl;
std::getchar();
// BEGIN CODE IN QUESTION
while (!queue.empty())
{
web::http::http_request request;
if (queue.pop(request))
request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
}
// END CODE IN QUESTION
listener.close().wait();

Второй фрагмент кода. Зависает от закрытия ().

    // hangs on close().wait()
web::http::http_request request;
while (queue.try_pop(request))
{
request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
}

Третий фрагмент кода. Зависает от закрытия ().

    // hangs on close().wait(). Outer braces make no difference.
{
web::http::http_request request;
while (queue.try_pop(request))
{
request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
request.~http_request();
}
}

Четвёртый фрагмент кода. Зависает от закрытия (). Внешние брекеты не имеют значения.

    // hangs on close().wait()
{
web::http::http_request request;
while (queue.try_pop(request))
{
request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
request.~http_request();
}
request.~http_request();
}

Обновление: поддерживая объяснение Мэтта Макнабба, следующий код работает, если я только выпускаю один GET. Я просто удалил цикл для обработки одного GET. Явный вызов деструктора требуется, чтобы избежать зависания, но это неправильная практика.

    web::http::http_request request;
requests.pop(request);
request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
request.~http_request();

Обновление: явный вызов деструктора после цикла заставляет программу работать для одного GET. Однако два или более GET выдают исключение. Я не уверен почему.

    web::http::http_request request;
while (queue.try_pop(request))
{
request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
}
request.~http_request();

1

Решение

Отказ от ответственности: без каких-либо знаний об этой библиотеке, это довольно опасно

#include <iostream>
using namespace std;

class Obj {
public:
Obj() {
cout << "Constructor" << endl;
}
~Obj() {
cout << "Destructor" << endl;
}
};

int main() {
{
Obj ea;
ea.~Obj();
}
return 0;
}

Выход:

Constructor
Destructor
Destructor

Если есть ресурсы, которые нужно освободить, или операции, которые нужно выполнить для очистки запроса, вы создаете много проблем в каждом случае, кроме случаев, когда вы выполняете следующие шаги:

  1. Получение запроса копией (pop или же try_pop)
  2. Обработка запроса
  3. Уничтожение и очистка запроса ОДИН РАЗ

В фрагментах выше:

  1. Объект копируется из очереди, обрабатывается и уничтожается. Каждый из них. хорошо.
  2. Объект скопирован, обработан, но не уничтожен. висит.
  3. Объект копируется, обрабатывается, уничтожается, а затем снова уничтожается. висит.
  4. Четное хуже чем 3.
  5. Объект копируется, обрабатывается и уничтожается. Прекрасно для слушателя, это может вызвать проблемы в конце области действия функции.
  6. Объект копируется, обрабатывается, и только один из них вызывает деструктор для очистки — таким образом, только один запрос. Штраф за один запрос.
1

Другие решения

Проблема с каждым из этих примеров, кажется, та же самая: несоответствующая конструкция и уничтожение объекта запроса. Я редко видел такую ​​изобретательность в том, чтобы делать это неправильно.

Простое решение:

  1. Объявите объект внутри блока, после чего он будет выделен.
  2. Не вызывайте деструктор явно (редко хорошая идея).
  3. Объект будет уничтожен при выходе из блока.

Казалось бы, его нужно уничтожить перед вызовом close (), что разумно.


Под этим я подразумеваю, что второй пример — единственный, в котором объект вообще не разрушен, и он тоже терпит неудачу. Я предполагаю, что это по какой-то другой причине не видно в этом коде.

2

По вопросам рекламы [email protected]