Skip to content

Commit 7cd3e45

Browse files
committed
Implement move semantics for context_t and socket_t classes
- Also disables copy in msg_t to avoid double free situations
1 parent 830a704 commit 7cd3e45

File tree

2 files changed

+65
-6
lines changed

2 files changed

+65
-6
lines changed

tests/proto/zmq_proto.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <assert.h>
22
#include <google/protobuf/wrappers.pb.h>
3+
#include <iostream>
34
#include <thread>
45
#include <tyndall/meta/macro.h>
56
#include <tyndall/proto/zmq_proto.h>
@@ -16,8 +17,23 @@
1617

1718
int main() {
1819
zmq_proto::context_t context{1};
19-
zmq_proto::socket_t<zmq_proto::PUB> pub(context, "tcp://*:5444");
20-
zmq_proto::socket_t<zmq_proto::SUB> sub(context, "tcp://127.0.0.1:5444");
20+
zmq_proto::socket_t<zmq_proto::PUB> pub_1(context, "tcp://*:5444");
21+
zmq_proto::socket_t<zmq_proto::SUB> sub_1(context, "tcp://127.0.0.1:5444");
22+
23+
auto handle_pub = pub_1.zmq_handle();
24+
auto handle_sub = sub_1.zmq_handle();
25+
26+
check(handle_pub != NULL);
27+
check(handle_sub != NULL);
28+
29+
zmq_proto::socket_t<zmq_proto::PUB> pub = std::move(pub_1);
30+
zmq_proto::socket_t<zmq_proto::SUB> sub = std::move(sub_1);
31+
32+
check(handle_pub == pub.zmq_handle());
33+
check(handle_sub == sub.zmq_handle());
34+
35+
check(pub_1.zmq_handle() == NULL);
36+
check(sub_1.zmq_handle() == NULL);
2137

2238
std::thread sub_thread([&sub]() {
2339
google::protobuf::Int32Value msg;

tyndall/proto/zmq_proto.h

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,19 @@ class context_t {
3939
zmq_proto_assert(rc == 0);
4040
}
4141

42+
// Implement move constructor
43+
context_t(context_t &&other) noexcept : context(other.context) {
44+
other.context = NULL; // Set the moved-from context to NULL
45+
}
46+
47+
context_t &operator=(context_t &&other) noexcept {
48+
if (this != &other && other.context != NULL) {
49+
context = other.context;
50+
other.context = NULL; // Set the moved-from context to NULL
51+
}
52+
return *this;
53+
}
54+
4255
int init(int n_threads) {
4356
context = zmq_ctx_new();
4457
zmq_proto_assert(context != NULL);
@@ -56,6 +69,12 @@ class context_t {
5669
void *zmq_handle() { return context; }
5770

5871
~context_t() {
72+
// Avoid double close
73+
if (context == NULL) {
74+
return;
75+
}
76+
printf("[ %s:%d %s ] Closing context %p\n", __FILE__, __LINE__, __func__,
77+
context);
5978
int rc;
6079
do {
6180
rc = zmq_ctx_destroy(context);
@@ -119,11 +138,29 @@ template <socket_type_t socket_type> class socket_t {
119138
}
120139
}
121140

141+
// Implement move constructor and assignment operator
142+
socket_t(socket_t &&other) noexcept : socket(other.socket) {
143+
other.socket = NULL; // Set the moved-from socket to NULL
144+
}
145+
socket_t &operator=(socket_t &&other) noexcept {
146+
if (this != &other && other.socket != NULL) {
147+
socket = other.socket;
148+
other.socket = NULL; // Set the moved-from socket to NULL
149+
}
150+
return *this;
151+
}
152+
122153
void *zmq_handle() const { return socket; }
123154

124155
void *zmq_handle() { return socket; }
125156

126157
~socket_t() {
158+
// Avoid double close
159+
if (socket == NULL) {
160+
return;
161+
}
162+
printf("[ %s:%d %s ] Closing socket %p\n", __FILE__, __LINE__, __func__,
163+
socket);
127164
int rc = zmq_close(socket);
128165
zmq_proto_assert(rc == 0);
129166

@@ -152,6 +189,12 @@ class msg_t {
152189
int rc = zmq_msg_close(&msg);
153190
zmq_proto_assert(rc == 0);
154191
}
192+
193+
// Disallow copy constructor, assignment operator and move operations
194+
msg_t(const msg_t &) = delete;
195+
msg_t &operator=(const msg_t &) = delete;
196+
msg_t(msg_t &&) = delete;
197+
msg_t &operator=(msg_t &&) = delete;
155198
};
156199

157200
// helpers:
@@ -324,10 +367,10 @@ int recv_more(::google::protobuf::MessageLite &proto_msg,
324367

325368
/*
326369
receives two parts of a multipart message. Matches first with type name and
327-
parses second into proto errno: EAGAIN if the inbound message queue was empty
328-
errno: EBADMSG if the type name didn't match
329-
errno: EOPNOTSUPP if there were no more message parts to receive after first
330-
part errno: EPROTO if the proto could not be parsed / did not match
370+
parses second into proto errno: EAGAIN if the inbound message queue was
371+
empty errno: EBADMSG if the type name didn't match errno: EOPNOTSUPP if
372+
there were no more message parts to receive after first part errno: EPROTO
373+
if the proto could not be parsed / did not match
331374
*/
332375
template <socket_type_t socket_type>
333376
int recv(::google::protobuf::MessageLite &proto_msg,

0 commit comments

Comments
 (0)