c++taskshared-ptrcontinuationsppl

shared_ptr vs. new operator: which one to use


In the function below I have made use of http_client from cpprestsdk (https://github.com/Microsoft/cpprestsdk) to make http requests to a network camera. The function below is probably a callback called by the lcm library (http://lcm-proj.github.io/) when a certain request is made.

I had problems with line 11. I was previously using the new operator:

auto init_session_response = new init_session_response_t;

to create the pointer and manually delete it just before exiting the function. But I got a access violation exception when trying to modify the init_session_response object in the pplx task continuation at line 49.

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

This problem went away when I started using std::shared_ptr. Can someone explain to me why using shared_ptr solved the problem? Should the http_client* also be created using std::shared_ptr?

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}

Solution

  • When you get violation access error, you must have deleted the pointer in some place in your code (e.g. in some then lambdas), but you did not post your code using raw pointer so I can not say which line.

    By using std::shared_ptr, when it's passed to the lambda, it's captured by value, so it increase the use_count and ensures that init_session_response is valid and not destructed in the labmda, which solves the issue.