diff --git a/CHANGELOG.md b/CHANGELOG.md index fb1eb768..9342c9b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ Version 147: * Don't use boost::string_ref * Use iterator wrapper in detail::buffers_range +WebSocket: + +* control callback is copied or moved + -------------------------------------------------------------------------------- Version 146: diff --git a/include/boost/beast/websocket/stream.hpp b/include/boost/beast/websocket/stream.hpp index b6d10834..0086d817 100644 --- a/include/boost/beast/websocket/stream.hpp +++ b/include/boost/beast/websocket/stream.hpp @@ -580,9 +580,9 @@ public: string_view payload // The payload in the frame ); @endcode - The implementation type-erases the callback without requiring - a dynamic allocation. For this reason, the callback object is - passed by a non-constant reference. + The implementation type-erases the callback which may require + a dynamic allocation. To prevent the possiblity of a dynamic + allocation, use `std::ref` to wrap the callback. If the read operation which receives the control frame is an asynchronous operation, the callback will be invoked using the same method as that used to invoke the final handler. @@ -592,15 +592,10 @@ public: Attempting to send a close frame after a close frame is received will result in undefined behavior. */ - template void - control_callback(Callback& cb) + control_callback(std::function cb) { - // Callback may not be constant, caller is responsible for - // managing the lifetime of the callback. Copies are not made. - BOOST_STATIC_ASSERT(! std::is_const::value); - - ctrl_cb_ = std::ref(cb); + ctrl_cb_ = std::move(cb); } /** Reset the control frame callback. diff --git a/test/beast/websocket/read.cpp b/test/beast/websocket/read.cpp index 577fb554..602a52e5 100644 --- a/test/beast/websocket/read.cpp +++ b/test/beast/websocket/read.cpp @@ -126,13 +126,13 @@ public: put(ws.next_layer().buffer(), cbuf( 0x89, 0x00)); bool invoked = false; - auto cb = [&](frame_type kind, string_view) - { - BEAST_EXPECT(! invoked); - BEAST_EXPECT(kind == frame_type::ping); - invoked = true; - }; - ws.control_callback(cb); + ws.control_callback( + [&](frame_type kind, string_view) + { + BEAST_EXPECT(! invoked); + BEAST_EXPECT(kind == frame_type::ping); + invoked = true; + }); w.write(ws, sbuf("Hello")); multi_buffer b; w.read(ws, b); @@ -147,13 +147,13 @@ public: put(ws.next_layer().buffer(), cbuf( 0x88, 0x00)); bool invoked = false; - auto cb = [&](frame_type kind, string_view) - { - BEAST_EXPECT(! invoked); - BEAST_EXPECT(kind == frame_type::close); - invoked = true; - }; - ws.control_callback(cb); + ws.control_callback( + [&](frame_type kind, string_view) + { + BEAST_EXPECT(! invoked); + BEAST_EXPECT(kind == frame_type::close); + invoked = true; + }); w.write(ws, sbuf("Hello")); doReadTest(w, ws, close_code::none); }); @@ -162,15 +162,14 @@ public: doTest(pmd, [&](ws_type& ws) { bool once = false; - auto cb = + ws.control_callback( [&](frame_type kind, string_view s) { BEAST_EXPECT(kind == frame_type::pong); BEAST_EXPECT(! once); once = true; BEAST_EXPECT(s == ""); - }; - ws.control_callback(cb); + }); w.ping(ws, ""); ws.binary(true); w.write(ws, sbuf("Hello")); @@ -185,15 +184,14 @@ public: doTest(pmd, [&](ws_type& ws) { bool once = false; - auto cb = + ws.control_callback( [&](frame_type kind, string_view s) { BEAST_EXPECT(kind == frame_type::pong); BEAST_EXPECT(! once); once = true; BEAST_EXPECT(s == "payload"); - }; - ws.control_callback(cb); + }); ws.ping("payload"); w.write_some(ws, false, sbuf("Hello, ")); w.write_some(ws, false, sbuf("")); diff --git a/test/doc/websocket_snippets.cpp b/test/doc/websocket_snippets.cpp index 4b1cc1e4..2f38506e 100644 --- a/test/doc/websocket_snippets.cpp +++ b/test/doc/websocket_snippets.cpp @@ -190,13 +190,12 @@ boost::asio::ip::tcp::socket sock{ioc}; { stream ws{ioc}; //[ws_snippet_17 - auto cb = + ws.control_callback( [](frame_type kind, string_view payload) { // Do something with the payload boost::ignore_unused(kind, payload); - }; - ws.control_callback(cb); + }); //] //[ws_snippet_18