Skip to content

Commit ee4419b

Browse files
committed
[新增 SafeCallback 模块]:实现生命周期安全的回调函数
- 在项目中新增 `SafeCallback` 模块,包含 `safecallback.hpp` 和 `safecallback_unittest.cc` 文件。 - `SafeCallback` 类通过 `std::weak_ptr` 管理对象生命周期,确保回调函数在对象销毁后不会被调用。 - 提供 `makeSafeCallback` 工厂函数,用于简化回调函数的创建。 - 编写单元测试 `safecallback_unittest.cc`,验证回调函数在对象存活和销毁后的行为。 - 更新 `CMakeLists.txt` 和 `README.md` 文件,将 `SafeCallback` 模块集成到项目中。
1 parent cb25fb7 commit ee4419b

File tree

5 files changed

+117
-2
lines changed

5 files changed

+117
-2
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ add_subdirectory(MonitorDir)
6868
add_subdirectory(MonitorDir_EFSW)
6969
add_subdirectory(Mutex)
7070
add_subdirectory(OpenSSL)
71+
add_subdirectory(SafeCallback)
7172
add_subdirectory(Thread)
7273

7374
if(CMAKE_HOST_LINUX)

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,11 @@
4646
7. [sm4](/OpenSSL/openssl_sm4.cc)——sm4加解密的例子;
4747
8. [x509](/OpenSSL/openssl_x509.cc)——x509证书的例子;
4848
9. [bash](/OpenSSL/openssl_bash.sh)——openssl命令行的例子;
49-
26. [Server](/Server)——linux server的一些例子;
49+
26. [SafeCallback](/SafeCallback/safecallback.hpp)——生命周期安全的回调函数的实现,参考[muduo WeakCallback](https://github.com/chenshuo/muduo/blob/cpp17/muduo/base/WeakCallback.h)
50+
27. [Server](/Server)——linux server的一些例子;
5051
1. [server_epoll](/Server/server_epoll.cc)——epoll的例子;
5152
2. [server_poll](/Server/server_poll.cc)——poll的例子;
5253
3. [server_select](/Server/server_select.cc)——select的例子;
53-
27. [Thread](/Thread/)——基于std::thread实现的线程类,包括线程池;
54+
28. [Thread](/Thread/)——基于std::thread实现的线程类,包括线程池;
5455
1. [Thread](/Thread/thread.hpp)——线程类;
5556
2. [ThreadPool](/Thread/threadpool.hpp)——线程池;

SafeCallback/CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
add_executable(safecallback_unittest safecallback_unittest.cc safecallback.hpp)
2+
target_link_libraries(
3+
safecallback_unittest PRIVATE GTest::gtest GTest::gtest_main GTest::gmock
4+
GTest::gmock_main)
5+
add_test(NAME safecallback_unittest COMMAND safecallback_unittest)

SafeCallback/safecallback.hpp

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#pragma once
2+
3+
#include <functional>
4+
#include <iostream>
5+
#include <memory>
6+
#include <utility>
7+
8+
template<typename CLASS, typename... ARGS>
9+
class SafeCallback
10+
{
11+
public:
12+
SafeCallback(const std::weak_ptr<CLASS> &object,
13+
const std::function<void(CLASS *, ARGS...)> &function)
14+
: m_object(object)
15+
, m_function(function)
16+
{}
17+
18+
template<typename... CallARGS>
19+
void operator()(CallARGS &&...args) const
20+
{
21+
if (auto ptr = m_object.lock()) {
22+
m_function(ptr.get(), std::forward<CallARGS>(args)...);
23+
} else {
24+
std::cout << "Callback object has been destroyed." << std::endl;
25+
}
26+
}
27+
28+
private:
29+
std::weak_ptr<CLASS> m_object;
30+
std::function<void(CLASS *, ARGS...)> m_function;
31+
};
32+
33+
template<typename CLASS, typename... ARGS>
34+
SafeCallback<CLASS, ARGS...> makeSafeCallback(const std::shared_ptr<CLASS> &object,
35+
void (CLASS::*function)(ARGS...))
36+
{
37+
return SafeCallback<CLASS, ARGS...>(object, function);
38+
}
39+
40+
template<typename CLASS, typename... ARGS>
41+
SafeCallback<CLASS, ARGS...> makeSafeCallback(const std::shared_ptr<CLASS> &object,
42+
void (CLASS::*function)(ARGS...) const)
43+
{
44+
return SafeCallback<CLASS, ARGS...>(object, function);
45+
}

SafeCallback/safecallback_unittest.cc

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include "safecallback.hpp"
2+
3+
#include <gtest/gtest.h>
4+
#include <iostream>
5+
#include <memory>
6+
#include <thread>
7+
8+
class MyClass
9+
{
10+
public:
11+
void notify(int value)
12+
{
13+
std::cout << "Received value: " << value << std::endl;
14+
received_value = value;
15+
}
16+
17+
int received_value = -1;
18+
};
19+
20+
int free_function_value = -1;
21+
22+
void freeFunction(int value)
23+
{
24+
std::cout << "Free function received value: " << value << std::endl;
25+
free_function_value = value;
26+
}
27+
28+
class SafeCallbackTest : public ::testing::Test
29+
{
30+
protected:
31+
void SetUp() override { free_function_value = -1; }
32+
};
33+
34+
TEST_F(SafeCallbackTest, MemberFunctionCallback)
35+
{
36+
auto obj = std::make_shared<MyClass>();
37+
SafeCallback callback = makeSafeCallback(obj, &MyClass::notify);
38+
39+
int test_value = 42;
40+
callback(test_value);
41+
42+
EXPECT_EQ(obj->received_value, test_value);
43+
}
44+
45+
TEST_F(SafeCallbackTest, MemberFunctionCallbackAfterObjectDestroyed)
46+
{
47+
auto obj = std::make_shared<MyClass>();
48+
SafeCallback callback = makeSafeCallback(obj, &MyClass::notify);
49+
50+
int initial_value = obj->received_value;
51+
obj.reset();
52+
int test_value = 42;
53+
callback(test_value);
54+
55+
EXPECT_EQ(initial_value, -1);
56+
EXPECT_EQ(free_function_value, -1);
57+
}
58+
59+
int main(int argc, char **argv)
60+
{
61+
::testing::InitGoogleTest(&argc, argv);
62+
return RUN_ALL_TESTS();
63+
}

0 commit comments

Comments
 (0)