0

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}
  • 3
    `shared_ptr` and `new` are not mutually exclusive, though it is good practice to generally keep them that way with `make_shared`. – chris Jul 12 '16 at 03:04
  • keep in mind with `delete` the consequences are instantaneous (more or less) - the objects cease to be valid. this is relevant when you're setting up a callback / task that will need to refer to the value after `delete` which could be outside of the procedure allocating the object (such as a lambda using the address as a captured value). – Xeren Narcy Jul 12 '16 at 03:06
  • Its probably better to post the code that *doesn't work* if you want us to figure out why it doesn't work. – Galik Jul 12 '16 at 03:52
  • Also consider using `std::unique_ptr` rather than `std::shared_ptr` if you never intend to share the pointer's ownership. – Galik Jul 12 '16 at 03:54

1 Answers1

1

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.

Mine
  • 4,123
  • 1
  • 25
  • 46