【问题标题】:shared_ptr vs. new operator: which one to useshared_ptr 与 new 运算符:使用哪一个
【发布时间】:2016-11-14 03:11:43
【问题描述】:

在下面的函数中,我使用了来自 cpprestsdk (https://github.com/Microsoft/cpprestsdk) 的 http_client 向网络摄像机发出 http 请求。下面的函数可能是当某个请求发出时,lcm 库 (http://lcm-proj.github.io/) 调用的回调。

我在第 11 行遇到了问题。我之前使用的是 new 运算符:

auto init_session_response = new init_session_response_t;

在退出函数之前创建指针并手动删除它。 但是在第 49 行尝试修改 pplx 任务继续中的 init_session_response 对象时出现访问冲突异常。

init_session_response->status_code =
              ptz_camera::status_codes_t::OK;

当我开始使用 std::shared_ptr 时,这个问题就消失了。有人可以向我解释为什么使用 shared_ptr 解决了这个问题吗?是否也应该使用 std::shared_ptr 创建 http_client*?

1 void lcm_handler::on_init_session_req(const lcm::ReceiveBuffer* rbuff,
2   const std::string& channel,
3   const ptz_camera::init_session_request_t* req)
4 {
5     std::cout << "Received init session req on channel: " << channel << 
6       "; Camera: " << req->ip_address << std::endl;
7 
8   auto ip_address = req->ip_address;
9 
10    // Note use of std::shared_ptr
11  auto init_session_response = make_shared<ptz_camera::init_session_response_t>();
12  
13  auto key_position = this->ip_client_map.find(ip_address);
14  if (key_position == ip_client_map.end())
15  {
16      std::cout << "Creating a new client for the ip: "
17          << req->ip_address << endl;
18
19      wstring username = this->convert_to_wstring(req->username);
20      wstring password = this->convert_to_wstring(req->password);
21
22      wstring main_uri = L"http://" + convert_to_wstring(ip_address);
23      auto config = http_client_config();
24      auto login = credentials(username, password);
25      config.set_credentials(login);
26      config.set_timeout(std::chrono::milliseconds(500));
27
28      http_client* client = new http_client(main_uri, config);
29      std::cout << "Client created...\n";
30
31      uri_builder uri = uri_builder(U("/") + uri_constants::stw_cgi).
32          append_path(uri_constants::attributes_cgi).append_path(uri_constants::attributes);
33
34      auto request = uri.to_string();
35  
36      client->request(methods::GET, request)
37          .then([this, ip_address, client, init_session_response]
38              (pplx::task<http_response> request_task) -> pplx::task<wstring>
39      {
40          try 
41          {
42              auto response = request_task.get();
43              if (response.status_code() == status_codes::OK)
44              {
45                  std::cout << "Saving client...";
46                  this->ip_client_map[ip_address] = client;
47                  std::cout << "success.\n";
48
49                  init_session_response->status_code =
50                  ptz_camera::status_codes_t::OK;
51              }
52
53              else
54              {
55                  cout << "GET request to client failed! HTTP Error: "
56                      << response.status_code() << std::endl;
57
58                  init_session_response->status_code =
59                      ptz_camera::status_codes_t::ERR;
60              }
61
62              return response.extract_string();
63          }
64              
65          catch (const exception& e)
66          {
67              cout << "Caught exception: " << e.what() << endl;
68              return create_task([e, this]() -> wstring
69              {
70                  return convert_to_wstring(e.what());
71              });
72          }               
73
74      })
75          .then([init_session_response, this](wstring response)
76      {
77          string n = this->convert_to_string(response);
78          init_session_response->response_message = n;
79      });
80  }
81
82
83  else
84  {
85      string message = "Client for ip: " + req->ip_address + " already exists\n";
86      cout << message << endl;
87      init_session_response->response_message = message;
88      init_session_response->status_code = ptz_camera::status_codes_t::OK;
89  }   
90
91  this->lcm->publish(ptz_camera_channels::init_session_res_channel,
92      init_session_response.get());   
93}

【问题讨论】:

  • shared_ptrnew 不是相互排斥的,但最好将它们与 make_shared 保持一致。
  • 请记住delete 的后果是瞬时的(或多或少)- 对象不再有效。这在您设置需要引用 delete 之后的值的回调/任务时是相关的,这可能在分配对象的过程之外(例如使用地址作为捕获值的 lambda)。
  • 如果您想让我们弄清楚为什么它不起作用,最好发布不起作用的代码
  • 如果您从不打算共享指针的所有权,也可以考虑使用std::unique_ptr 而不是std::shared_ptr

标签: c++ task shared-ptr continuations ppl


【解决方案1】:

当您遇到违规访问错误时,您必须在代码中的某个位置删除了指针(例如,在某些then lambdas 中),但是您没有使用原始指针发布您的代码,所以我不能说是哪一行。

通过使用std::shared_ptr,当它传递给lambda时,它是按值捕获的,因此它增加了use_count,并确保init_session_response在labmda中有效且不被破坏,从而解决了问题。

【讨论】:

    猜你喜欢
    • 2017-02-18
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 2013-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多