Skip to content

Commit

Permalink
[新增 SafeCallback 模块]:实现生命周期安全的回调函数
Browse files Browse the repository at this point in the history
- 在项目中新增 `SafeCallback` 模块,包含 `safecallback.hpp` 和 `safecallback_unittest.cc` 文件。
- `SafeCallback` 类通过 `std::weak_ptr` 管理对象生命周期,确保回调函数在对象销毁后不会被调用。
- 提供 `makeSafeCallback` 工厂函数,用于简化回调函数的创建。
- 编写单元测试 `safecallback_unittest.cc`,验证回调函数在对象存活和销毁后的行为。
- 更新 `CMakeLists.txt` 和 `README.md` 文件,将 `SafeCallback` 模块集成到项目中。
  • Loading branch information
RealChuan committed Jan 22, 2025
1 parent cb25fb7 commit ee4419b
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 2 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ add_subdirectory(MonitorDir)
add_subdirectory(MonitorDir_EFSW)
add_subdirectory(Mutex)
add_subdirectory(OpenSSL)
add_subdirectory(SafeCallback)
add_subdirectory(Thread)

if(CMAKE_HOST_LINUX)
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@
7. [sm4](/OpenSSL/openssl_sm4.cc)——sm4加解密的例子;
8. [x509](/OpenSSL/openssl_x509.cc)——x509证书的例子;
9. [bash](/OpenSSL/openssl_bash.sh)——openssl命令行的例子;
26. [Server](/Server)——linux server的一些例子;
26. [SafeCallback](/SafeCallback/safecallback.hpp)——生命周期安全的回调函数的实现,参考[muduo WeakCallback](https://github.com/chenshuo/muduo/blob/cpp17/muduo/base/WeakCallback.h)
27. [Server](/Server)——linux server的一些例子;
1. [server_epoll](/Server/server_epoll.cc)——epoll的例子;
2. [server_poll](/Server/server_poll.cc)——poll的例子;
3. [server_select](/Server/server_select.cc)——select的例子;
27. [Thread](/Thread/)——基于std::thread实现的线程类,包括线程池;
28. [Thread](/Thread/)——基于std::thread实现的线程类,包括线程池;
1. [Thread](/Thread/thread.hpp)——线程类;
2. [ThreadPool](/Thread/threadpool.hpp)——线程池;
5 changes: 5 additions & 0 deletions SafeCallback/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
add_executable(safecallback_unittest safecallback_unittest.cc safecallback.hpp)
target_link_libraries(
safecallback_unittest PRIVATE GTest::gtest GTest::gtest_main GTest::gmock
GTest::gmock_main)
add_test(NAME safecallback_unittest COMMAND safecallback_unittest)
45 changes: 45 additions & 0 deletions SafeCallback/safecallback.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#pragma once

#include <functional>
#include <iostream>
#include <memory>
#include <utility>

template<typename CLASS, typename... ARGS>
class SafeCallback
{
public:
SafeCallback(const std::weak_ptr<CLASS> &object,
const std::function<void(CLASS *, ARGS...)> &function)
: m_object(object)
, m_function(function)
{}

template<typename... CallARGS>
void operator()(CallARGS &&...args) const
{
if (auto ptr = m_object.lock()) {
m_function(ptr.get(), std::forward<CallARGS>(args)...);
} else {
std::cout << "Callback object has been destroyed." << std::endl;
}
}

private:
std::weak_ptr<CLASS> m_object;
std::function<void(CLASS *, ARGS...)> m_function;
};

template<typename CLASS, typename... ARGS>
SafeCallback<CLASS, ARGS...> makeSafeCallback(const std::shared_ptr<CLASS> &object,
void (CLASS::*function)(ARGS...))
{
return SafeCallback<CLASS, ARGS...>(object, function);
}

template<typename CLASS, typename... ARGS>
SafeCallback<CLASS, ARGS...> makeSafeCallback(const std::shared_ptr<CLASS> &object,
void (CLASS::*function)(ARGS...) const)
{
return SafeCallback<CLASS, ARGS...>(object, function);
}
63 changes: 63 additions & 0 deletions SafeCallback/safecallback_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include "safecallback.hpp"

#include <gtest/gtest.h>
#include <iostream>
#include <memory>
#include <thread>

class MyClass
{
public:
void notify(int value)
{
std::cout << "Received value: " << value << std::endl;
received_value = value;
}

int received_value = -1;
};

int free_function_value = -1;

void freeFunction(int value)
{
std::cout << "Free function received value: " << value << std::endl;
free_function_value = value;
}

class SafeCallbackTest : public ::testing::Test
{
protected:
void SetUp() override { free_function_value = -1; }
};

TEST_F(SafeCallbackTest, MemberFunctionCallback)
{
auto obj = std::make_shared<MyClass>();
SafeCallback callback = makeSafeCallback(obj, &MyClass::notify);

int test_value = 42;
callback(test_value);

EXPECT_EQ(obj->received_value, test_value);
}

TEST_F(SafeCallbackTest, MemberFunctionCallbackAfterObjectDestroyed)
{
auto obj = std::make_shared<MyClass>();
SafeCallback callback = makeSafeCallback(obj, &MyClass::notify);

int initial_value = obj->received_value;
obj.reset();
int test_value = 42;
callback(test_value);

EXPECT_EQ(initial_value, -1);
EXPECT_EQ(free_function_value, -1);
}

int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

0 comments on commit ee4419b

Please sign in to comment.