From 73bc74a13c877646f8a075de6c30fb65a370fa88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Kn=C3=A1pek?= Date: Wed, 8 Oct 2025 19:15:55 +0200 Subject: [PATCH 1/3] Avoid footgun. Factor temporary std::string instance to separate variable as this prolongs its lifetime long enough for result of .c_str to survive. Otherwise printf could obtain pointer to already destructed string. For more information consult GotW #88 at [1]. [1] https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/ --- echo_server.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/echo_server.cpp b/echo_server.cpp index fe3dfea..141d8dc 100644 --- a/echo_server.cpp +++ b/echo_server.cpp @@ -22,7 +22,8 @@ void handle_request(const std::error_code& error, tcp::socket socket) { server.async_accept(io, &handle_request); // The Loop if (error) { - printf("Error while accepting: %s\n", error.message().c_str()); + const auto &msg = error.message(); + printf("Error while accepting: %s\n", msg.c_str()); return; } @@ -33,14 +34,16 @@ void handle_request(const std::error_code& error, tcp::socket socket) { asio::async_read_until(request->socket, request->buffer, '\n', [request](const auto &error, size_t bytes_transferred) { if (error) { - printf("Error while reading: %s\n", error.message().c_str()); + const auto &msg = error.message(); + printf("Error while reading: %s\n", msg.c_str()); return; } printf("Received %zu bytes\n", bytes_transferred); asio::async_write(request->socket, request->buffer, [request](const auto &error, size_t bytes_transferred) { if (error) { - printf("Error while writing: %s\n", error.message().c_str()); + const auto &msg = error.message(); + printf("Error while writing: %s\n", msg.c_str()); return; } printf("Sent %zu bytes\n", bytes_transferred); From 9b08d8d3fb2f119546c0d63a341850037d15eb80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Kn=C3=A1pek?= Date: Wed, 8 Oct 2025 19:18:28 +0200 Subject: [PATCH 2/3] Use {} instead of () for object construction. Sometimes it is difficult to distinguish between a function call and object construction. It is better to use {} for object construction for this reason. --- echo_server.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/echo_server.cpp b/echo_server.cpp index 141d8dc..b1fd626 100644 --- a/echo_server.cpp +++ b/echo_server.cpp @@ -6,7 +6,7 @@ using asio::ip::tcp; const size_t port = 6970; asio::io_context io; -asio::ip::tcp::acceptor server(io, tcp::endpoint(tcp::v4(), port)); +asio::ip::tcp::acceptor server{io, tcp::endpoint{tcp::v4(), port}}; class Request { public: @@ -54,7 +54,7 @@ void handle_request(const std::error_code& error, tcp::socket socket) { int main() { size_t seconds = 5; - asio::steady_timer t(io, asio::chrono::seconds(seconds)); + asio::steady_timer t{io, asio::chrono::seconds{seconds}}; printf("Waiting for %zu seconds\n", seconds); t.async_wait([seconds](const std::error_code &e) { printf("------------------------------\n"); From 36efa17a786948fe44fa735a0e9d79759f66da26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Kn=C3=A1pek?= Date: Wed, 8 Oct 2025 19:18:47 +0200 Subject: [PATCH 3/3] std::unique_ptr baby Captures in lambdas are const by default. So in order to be able to move from them, we mark the entire lambda as mutable. Thus, member variables in our closure object are no longer const. Also, using a variable multiple times on the same line and one of the uses is modifying the variable is a no-no. Extract the pointer out of the unique_ptr before performing modifying operation. --- echo_server.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/echo_server.cpp b/echo_server.cpp index b1fd626..c584782 100644 --- a/echo_server.cpp +++ b/echo_server.cpp @@ -27,20 +27,22 @@ void handle_request(const std::error_code& error, tcp::socket socket) { return; } - auto request = std::make_shared(std::move(socket)); + auto request = std::make_unique(std::move(socket)); printf("Accepted connection\n"); - asio::async_read_until(request->socket, request->buffer, '\n', - [request](const auto &error, size_t bytes_transferred) { + auto req = request.get(); + asio::async_read_until(req->socket, req->buffer, '\n', + [request = std::move(request)](const auto &error, size_t bytes_transferred) mutable { if (error) { const auto &msg = error.message(); printf("Error while reading: %s\n", msg.c_str()); return; } printf("Received %zu bytes\n", bytes_transferred); - asio::async_write(request->socket, request->buffer, - [request](const auto &error, size_t bytes_transferred) { + auto req = request.get(); + asio::async_write(req->socket, req->buffer, + [request = std::move(request)](const auto &error, size_t bytes_transferred) mutable { if (error) { const auto &msg = error.message(); printf("Error while writing: %s\n", msg.c_str());