gpt4 book ai didi

c++ - 将 userData 从回调开始传递到回调结束

转载 作者:行者123 更新时间:2023-11-28 01:40:33 27 4
gpt4 key购买 nike

如何适本地缓存从用户的 callbackBegin() 生成的 userData并发送给用户的callbackEnd() .

简单版本(无用户数据 - demo)

我想创建一个支持回调的复杂数据库。对于 MCVE,假设它是 MyArray .

这是一个支持回调但没有userData的简单数组类。

#include <iostream>
template<class Derived>class MyArray{ //library - I design it.
public: void push_back(int s){
static_cast<Derived*>(this)->callbackBegin(s);
//do something about array
static_cast<Derived*>(this)->callbackEnd(s);
}
//other fields / functions
};
class Callback : public MyArray<Callback>{ //user's class
public: void callbackBegin(int s){
std::cout<<"callbackBegin"<<std::endl;
}
public: void callbackEnd(int s){
std::cout<<"callbackEnd"<<std::endl;
}
};
int main() {
Callback c;
c.push_back(5); //print: callbackBegin callbackEnd
return 0;
}

它工作正常。

下一步:我想从 Callback::callbackBegin() 传递一些userDataCallback::callbackEnd() .
例如,userDataCallback::callbackBegin() 时的时钟时间叫做。

我糟糕的解决方案 ( void*& userdata : demo )

这是我尝试实现它的尝试:-

#include <iostream>
#include <time.h>
template<class Derived>class MyArray{
public: void push_back(int s){
void* userData=nullptr; //#
static_cast<Derived*>(this)->callbackBegin(s,userData); //# ugly
//do something about array
static_cast<Derived*>(this)->callbackEnd(s,userData); //# ugly
}
};
class Callback : public MyArray<Callback>{
public: void callbackBegin(int s,void*& userData){ //#
userData=new clock_t(clock()); //# danger
std::cout<<"callbackBegin"<<std::endl;
}
public: void callbackEnd(int s,void*& userData){ //#
clock_t* userDataTyped=static_cast<clock_t*>(userData);
clock_t clock2=clock();
clock_t different=clock2 - (*userDataTyped);
std::cout<<"callbackEnd time(second)="
<<((float)different)/CLOCKS_PER_SEC<<std::endl;
delete userDataTyped; //# danger
}
};
int main() {
Callback c;
c.push_back(5); //print: callbackBegin callbackEnd time(second)=8.5e-05
return 0;
}

它也可以正常工作,但我认为这是一个糟糕的设计(在各种 # ):-

  • new/delete在 2 个地方:潜在的内存泄漏。
    强指针是首选,但我不知道如何。
  • static_cast<clock_t*>(userData)是代码味道,至少对我而言。
  • (小问题)一个额外丑陋的参数 void*&

问题: 什么是设计模式/C++ 魔法来避免此类问题,同时 make MyArray简洁、易于使用、可维护(即不比简单版本差多少)?

其他注意事项:

  • 在实际情况下,<5% 的用户回调类需要userData
    因此,我很不愿意添加 void&*作为一个额外的参数。
    澄清:(已编辑)少数案例通常需要不同类型的userData,例如Callback1需要clock_t , Callback2需要std::string

  • 建议的解决方案应限制使用 std::function<>virtual function ,因为性能是这里的主要关注点。

谢谢。

最佳答案

通过 void 指针传递数据是一个很好的 C 解决方案,但(恕我直言)不是 C++(特别是:不是 C++11/c++14/C++17,autostd::tuple) 不错。

所以我建议从 callbackBegin() 返回一个值,并将该值作为第一个参数传递给 `callbackEnd();像

  auto r = static_cast<Derived*>(this)->callbackBegin(s);

static_cast<Derived*>(this)->callbackEnd(r, s);

观察(C++11 和更新的魔法)使用 auto 作为 callbackBegin() 返回值的类型,你可以从不同的 `callbackBegin 返回不同的类型().

额外建议:在 MyArray::push_back() 中更通用:使用可变参数模板,不需要固定 callbackBack()< 接收的参数的数量和类型callbackEnd()

使用可变参数模板,您可以如下修改 push_back()

template <typename ... Args>
void push_back (Args const & ... args)
{
auto r = static_cast<Derived*>(this)->callbackBegin(args...);

static_cast<Derived*>(this)->callbackEnd(r, args...);
}

下面是一个完整的工作示例,包含两个不同的回调类(具有不同数量的参数和不同的返回类型)

#include <tuple>
#include <iostream>

template <typename derT>
struct myA
{
template <typename ... Args>
void push_back (Args const & ... args)
{
auto r = static_cast<derT*>(this)->callbackBegin(args...);

static_cast<derT*>(this)->callbackEnd(r, args...);
}
};

struct cb1 : public myA<cb1>
{
int callbackBegin (int s)
{ std::cout << "cb1 b" << std::endl; return s+5; }

void callbackEnd (int r, int s)
{ std::cout << "cb1 e -" << r << ", " << s << std::endl; }
};

struct cb2 : public myA<cb2>
{
std::tuple<std::string, int> callbackBegin (std::string const & name,
int num)
{ std::cout << "cb2 b" << std::endl; return {name+";", num+1}; }

void callbackEnd (std::tuple<std::string, int> const &,
std::string const & name, int num)
{ std::cout << "cb2 e -" << name << ", " << num << std::endl; }
};

int main ()
{
cb1 c1;
c1.push_back(5);

cb2 c2;
c2.push_back("string arg", 7);

return 0;
}

关于c++ - 将 userData 从回调开始传递到回调结束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47327402/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com