学习c ++并尝试熟悉一些模式.该signals2 DOC显然有事情,我可以插槽和信号做繁多.我不明白的是我应该使用哪种类型的应用程序(用例).
我正在考虑调度变更事件的状态机.来自动态类型的背景(C#,Java等),您将使用事件调度程序或静态引用或回调.
使用跨类回调在c ++中是否存在困难?这就是为什么信号2存在的原因?
示例案例之一是文档/视图.这种模式如何比使用函数向量并在循环中调用每个函数更好地适用,或者说在注册的侦听类实例中调用状态更改的lambda?
class Document
{
public:
typedef boost::signals2::signal<void ()> signal_t;
public:
Document()
{}
/* Connect a slot to the signal which will be emitted whenever
text is appended to the document. */
boost::signals2::connection connect(const signal_t::slot_type &subscriber)
{
return m_sig.connect(subscriber);
}
void append(const char* s)
{
m_text += s;
m_sig();
}
const std::string& getText() const
{
return m_text;
}
private:
signal_t m_sig;
std::string m_text;
};
Run Code Online (Sandbox Code Playgroud)
和
class TextView
{
public: …Run Code Online (Sandbox Code Playgroud) 我发现boost :: signals2使用了一些连接槽的延迟删除,这使得很难将连接用作管理对象生命周期的东西.我正在寻找一种方法来强制插槽在断开连接时直接删除.如何通过不同的方式设计我的代码来解决问题的任何想法也很感激!
这是我的场景:我有一个Command类负责执行异步需要时间的事情,看起来像这样(简化):
class ActualWorker {
public:
boost::signals2<void ()> OnWorkComplete;
};
class Command : boost::enable_shared_from_this<Command> {
public:
...
void Execute() {
m_WorkerConnection = m_MyWorker.OnWorkDone.connect(boost::bind(&Command::Handle_OnWorkComplete, shared_from_this());
// launch asynchronous work here and return
}
boost::signals2<void ()> OnComplete;
private:
void Handle_OnWorkComplete() {
// get a shared_ptr to ourselves to make sure that we live through
// this function but don't keep ourselves alive if an exception occurs.
shared_ptr<Command> me = shared_from_this();
// Disconnect from the signal, ideally deleting the slot object …Run Code Online (Sandbox Code Playgroud) 我正在使用带有以下Boost Signals2代码的Visual Studio 2012 Ultimate:https://github.com/cfobel/boost_signals2/blob/master/hello_world_0.cpp 它会生成以下错误:
c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory(348): error C4996: 'std::_Uninitialized_copy0': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory(333) : see declaration of 'std::_Uninitialized_copy0'
1> c:\libraries\boost_1_52_0\boost\signals2\detail\auto_buffer.hpp(192) : see reference to function template instantiation '_FwdIt std::uninitialized_copy<I,boost::variant<T0_,T1>*>(_InIt,_InIt,_FwdIt)' …Run Code Online (Sandbox Code Playgroud) 我必须编写一个执行高度计算密集型计算的程序.该程序可能会运行几天.可以在不同的线程中轻松分离计算,而无需共享数据.我想要一个GUI或一个Web服务,告诉我当前的状态.
我目前的设计使用BOOST :: signals2和BOOST :: thread.它编译并到目前为止按预期工作.如果一个线程完成一次迭代并且有新数据可用,则它会调用一个连接到GUI类中的插槽的信号.
我的问题:
以下代码编译
g++ -Wall -o main -lboost_thread-mt <filename>.cpp
Run Code Online (Sandbox Code Playgroud)
代码如下:
#include <boost/signals2.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <iterator>
#include <string>
using std::cout;
using std::cerr;
using std::string;
/**
* Called when a CalcThread finished a new bunch of data.
*/
boost::signals2::signal<void(string)> signal_new_data;
/**
* The whole data will be stored here.
*/
class DataCollector
{
typedef boost::mutex::scoped_lock scoped_lock;
boost::mutex mutex;
public:
/**
* Called by CalcThreads call the …Run Code Online (Sandbox Code Playgroud) 我已经boost::signals2在我的项目中使用了一段时间.令我感到羞耻的是,我仍然不明白它们是如何在引擎盖下实现的.我的问题已经从信号的定义开始了.如何定义如
boost::signals2::signal< void (bool, double) >
Run Code Online (Sandbox Code Playgroud)
如何处理?我可以从实现细节中看到签名成为一个适当命名的模板参数Signature.但是,我不懂语法.C++标准是否允许这种语法?如果以这种形式提供功能签名,信号如何"存储"?
我已经尝试查看源代码,但无法找到此语法的解释.任何帮助,将不胜感激.
我整天都在使用Boost :: Signals2库从代码部分中获取编译器错误.我已经将我想要做的事情简化为一个最小的例子:
#include <boost/signals2.hpp>
int foo();
struct first_nonzero
{
using result_type = int;
template <typename It>
result_type operator()(It first, It last) const
{
while(first != last)
{
if(*first != 0)
{
return *first;
}
}
return 0;
}
};
int foo()
{
using signal = boost::signals2::signal<int (), first_nonzero>;
signal s;
return s();
}
Run Code Online (Sandbox Code Playgroud)
当我尝试编译此代码段时
clang -o foo.o -c foo.cpp -std=c++11 -Weverything -Wno-c++98-compat
Run Code Online (Sandbox Code Playgroud)
我得到一个模板推导错误,似乎来自信号库本身:
In file included from foo.cpp:1:
In file included from /usr/include/boost/signals2.hpp:19:
In file included from /usr/include/boost/signals2/signal.hpp:38:
In …Run Code Online (Sandbox Code Playgroud) 我想序列化boost :: signals2信号的多线程调用,以确保来自对象的状态变化的通知以明确定义的顺序到达插槽.
背景
我有一个在多线程程序中具有内部状态的对象.内部状态的某些部分对程序的其他部分很有意义,并且对象通过使用boost :: signals2信号来暴露状态更改,类似于:
class ObjectWithState {
public:
enum State {
STATE_A,
STATE_B,
STATE_C,
};
void OnEvent() {
State newState;
{
boost::lock_guard<boost::mutex> lock(m_Mutex);
// Process event and change state
m_State = ...;
newState = m_State;
}
m_OnStateChanged(newState);
}
// method to allow external objects to connect to the signal etc
private:
boost::signals2::signal<void (State) > m_OnStateChanged;
boost::mutex m_Mutex;
State m_State;
};
Run Code Online (Sandbox Code Playgroud)
问题
如果OnEvent处理程序有多个并发调用,这可能会导致侦听器收到有关状态更改的通知,而不是实际发生的更改.状态本身受上面的互斥锁保护,因此实际状态是明确定义的.但是,在对信号的调用中不能保持互斥锁,因为这可能导致死锁.这意味着信号的实际调用可能以任何顺序发生,而我要求它们以与实际发生状态变化相同的顺序被调用.
处理此问题的一种方法是从信号中删除状态,并通知侦听器状态已更改.然后,他们可以查询对象的状态,并获得对象在触发信号时的状态或以后的状态.在我的场景中,需要告知侦听器所有状态更改,因此此方法在此处不起作用.
我的下一个方法是如下:
class ObjectWithState {
public:
enum State { …Run Code Online (Sandbox Code Playgroud) 我最近一直在boost::signals2为学习目的而玩,我想知道我是否可以将信号连接到一个类中的非静态插槽(就像我在Qt中那样).考虑以下:
class Worker {
typedef boost::signals2::signal<void (const std::string &)> SendMessage;
public:
typedef SendMessage::slot_type SendMessageSlotType;
boost::signals2::connection connect(const SendMessageSlotType &slot) {
return send_message.connect(slot);
}
private:
SendMessage send_message;
};
class Controller {
public:
Controller() {
worker.connect(&Controller::print);
}
private:
static void print(const std::string &message) {
std::cout << message << std::endl;
}
Worker worker;
};
Run Code Online (Sandbox Code Playgroud)
现在我想创建Controller::print一个非静态成员.与boost::thread例如,这可以使用来实现boost::bind; 有没有办法做到这一点boost::signals2?
是否有某种方法可以覆盖在 boost::signals2 中调用插槽并执行某些操作(日志记录、调试、异常处理)的特定时刻?
我想在槽调用时捕获异常,因为信号/槽是我的代码中的执行路径在各种软件组件之间交叉的地方,每个组件都是可选的/可以在运行时被禁用,如果它行为不端。因此,当插槽调用抛出(可能来自外部库,可能只是 std::bad_alloc)时,我希望收到有关它的通知——并知道哪个组件被发送到了——这样我就可以终止该组件。
我不知道如何在组合器中做到这一点,因为我无法访问那里的插槽或连接对象?所以我看不到获取任何信息的方法。(在每个插槽上更改返回类型是不可行的。)
有没有一些我错过的超级简单的方法来做到这一点?
如果没有,我该怎么办?
将诸如 slot_call_iterator(在 try/catch 中包装调用)和 connection_body_base(例如存储有关它属于哪个组件的信息)之类的东西子类化,并让 boost 使用这些?(如何?)
或者子类signals2::slot<...>,在构造函数中为其提供有关拥有组件的信息并以某种方式重载operator()(...)?(也不知道这一点,使用所有模板魔法似乎更难。)
在限制的环境中C++03,boost::signals2与组件一起使用boost::function并boost::bind在组件之间实现简单的消息传递系统.它工作得很好,我也没有任何问题.
但是,在另一个完全支持的环境中C++11,boost::signals2对于非常简单的应用程序来说是否过度杀伤?
为了澄清,通过简单的我的意思是下列:
void性能是这个应用程序的关键,因此boost::signals2应用程序不需要的所有奇迹可能弊大于利.
现在,只需要std::vector<std::function>处理这个,并切换到其他东西,boost::signals2如果它被认为是合适的话会非常简单.
boost-signals2 ×10
c++ ×10
boost ×8
c++11 ×2
boost-thread ×1
clang ×1
events ×1
future ×1
non-static ×1
templates ×1