C++ 内存管理思想,std::map,boost::shared_ptr
这个问题很长,请耐心听我说 我正试图解决我在内存管理、共享指针和映射方面所面临的困境。我只是想得到一些关于我的架构的反馈,也许你们中的一些人在过去会做得更好 下面的例子将做的是伪代码 我有一个监听器类:C++ 内存管理思想,std::map,boost::shared_ptr,c++,design-patterns,shared-ptr,observer-pattern,command-pattern,C++,Design Patterns,Shared Ptr,Observer Pattern,Command Pattern,这个问题很长,请耐心听我说 我正试图解决我在内存管理、共享指针和映射方面所面临的困境。我只是想得到一些关于我的架构的反馈,也许你们中的一些人在过去会做得更好 下面的例子将做的是伪代码 我有一个监听器类: class MyListener { friend class Command; public: MyListener() {} virtual ~MyListener() {} void handleUpdate() { s
class MyListener {
friend class Command;
public:
MyListener() {}
virtual ~MyListener() {}
void handleUpdate() {
std::cout << "Update Handled" << std::endl;
}
};
问题就在这里。管理该消息的类是一个单例类,它使用两个方法publish和subscribe来发布DDS消息或订阅DDS消息。subscribe方法接受一个键值和一个原始指针
单身汉管理着一个家庭
std::map<std::string name, Command>
std::map
其中命令类包含MyListener类
下面是一段破坏它的伪代码:
class TaterTotListener : public MyListener {
void handleCommand() {
std::cout << "Tater tot found" << std::endl;
}
};
int main() {
// make a new smart pointer to the listener
boost::shared_ptr<TaterTotListener> ttl(new TaterTotListener);
// tell the singleton we want to publish an object called "TaterTot"
CommandManager::instance()->publish("TaterTot");
// tell the singleton we want to subscribe to an object called tater tot
CommandManager::isntance()->subscribe("TaterTot", ttl.get());
// processing goes here
// deallocation
}
class-tatertListener:public-MyListener{
void handleCommand(){
std::cout subscribe(“TaterTot”,ttl.get());
//处理在这里进行
//解除分配
}
解除分配后,boost将删除其对共享指针的所有权。CommandManager尝试通过删除所有名为“TaterTot”的对象来“清理”,但由于boost::shared_ptr已经清除了自身,因此会引发双重可用内存损坏。CommandManager singleton总是最后清除,因此声明原始指针并传递给subscribe方法将导致相同的行为
有什么想法吗?我是否错过了一些明显和直观的东西?我是否误解了共享指针在本例中的用法
非常感谢您的帮助。我会给您买一杯啤酒。您的设计融合了两种著名的设计模式,并且 Observer定义对象之间的一对多依赖关系,以便在一个对象发生更改时 状态下,将自动通知并更新其所有从属客户端 命令将请求封装为对象,从而使您可以使用 不同的请求、队列或日志请求,并支持可撤消的操作
我建议您研究这些模式(请参见上面的链接),并重构您的设计,将请求的封装与对这些请求的观察分开。您的设计混合了两种著名的设计模式,并且 Observer定义对象之间的一对多依赖关系,以便在一个对象发生更改时 状态下,将自动通知并更新其所有从属客户端 命令将请求封装为对象,从而使您可以使用 不同的请求、队列或日志请求,并支持可撤消的操作
我建议研究这些模式(参见上面的链接)重构您的设计,将请求的封装与对这些请求的观察分开。首先,我建议在另一个答案中遵循rhalbersma的建议。此外,我会再次检查您是否需要单例。从您所描述的内容中,我看不出它的强烈需求 从技术上讲,这是一个所有权问题。您提供的信息需要我猜测几件事。我认为
MyListener
实例应该在不同的东西之间共享,命令
对象和其他东西(因为您使用了共享\u ptr
)。因此,您需要通过以下方式真正共享此所有权:
class Command {
private:
boost::shared_ptr<MyListener> m_listener;
};
因此,我的Listener将由最后一位所有者出售。首先,我建议在另一个答案中遵循rhalbersma的建议。此外,我会再次检查您是否需要singleton。从您的描述中,我看不出它的强烈需求 从技术上讲,这是一个所有权问题。您提供的信息需要我猜测几件事。我认为
MyListener
实例应该在不同的东西之间共享,命令
对象和其他东西(因为您使用了共享\u ptr
)。因此,您需要通过以下方式真正共享此所有权:
class Command {
private:
boost::shared_ptr<MyListener> m_listener;
};
因此,MyListener将由最后一位所有者解除分配。多亏了贡献者,我按照@rhalbersma的建议,使用Observer设计模式创建了一个最小的、可编译的示例,完全符合我的要求
#include <cstdlib>
#include <iostream>
#include <map>
#include <boost/shared_ptr.hpp>
#include <vector>
class Listener {
public:
virtual void handleUpdate() = 0;
std::string *string;
};
class Command {
std::vector<boost::shared_ptr<Listener> > listener;
public:
~Command() {
}
void setListener(boost::shared_ptr<Listener> l) {
listener.push_back(l);
}
void handleCommand() {
for (int i = 0; i < listener.size(); i++) {
//std::cout << "Handle command " << i << std::endl;
listener.at(i)->string = string;
listener.at(i)->handleUpdate();
}
}
void write(std::string value) {
std::cout << "Write 1" << std::endl;
string = &value;
handleCommand();
}
private:
std::string *string;
};
class MyListener : public Listener {
public:
MyListener(int num) : num(num) {
};
~MyListener() {
}
void handleUpdate() {
std::cout << "Listener " << num << " with string " << *string << std::endl;
}
private:
int num;
};
class CommandManager {
public:
void publish(std::string name, std::string value) {
std::map<std::string, boost::shared_ptr<Command> >::iterator it;
it = commandMap.find(name);
if (it == commandMap.end()) {
// add a new one
boost::shared_ptr<Command> command(new Command());
commandMap[name] = command;
}
it = commandMap.find(name);
it->second->write(value);
}
void subscribe(std::string name, boost::shared_ptr<Listener> l) {
std::map<std::string, boost::shared_ptr<Command> >::iterator it;
it = commandMap.find(name);
if (it == commandMap.end()) {
boost::shared_ptr<Command> command(new Command());
command->setListener(l);
commandMap[name] = command;
} else {
it->second->setListener(l);
}
}
private:
std::map<std::string, boost::shared_ptr<Command> > commandMap;
};
int main(int argc, char** argv) {
boost::shared_ptr<MyListener> myListener0(new MyListener(0));
boost::shared_ptr<MyListener> myListener1(new MyListener(1));
boost::shared_ptr<MyListener> myListener2(new MyListener(2));
CommandManager commandManager;
commandManager.subscribe("Tyler", myListener0);
commandManager.subscribe("Tyler", myListener1);
commandManager.subscribe("Tyler", myListener2);
commandManager.publish("Tyler", " is cool");
return 0;
}
#包括
#包括
#包括
#包括
#包括
类侦听器{
公众:
虚拟void handleUpdate()=0;
std::string*string;
};
类命令{
向量监听器;
公众:
~Command(){
}
void setListener(boost::shared_ptr l){
监听器。推回(l);
}
void handleCommand(){
对于(int i=0;i //std::cout多亏了贡献者,我已经成功地创建了一个最小的、可编译的示例,使用@rhalbersma所建议的Observer设计模式,完全满足了我的需要
#include <cstdlib>
#include <iostream>
#include <map>
#include <boost/shared_ptr.hpp>
#include <vector>
class Listener {
public:
virtual void handleUpdate() = 0;
std::string *string;
};
class Command {
std::vector<boost::shared_ptr<Listener> > listener;
public:
~Command() {
}
void setListener(boost::shared_ptr<Listener> l) {
listener.push_back(l);
}
void handleCommand() {
for (int i = 0; i < listener.size(); i++) {
//std::cout << "Handle command " << i << std::endl;
listener.at(i)->string = string;
listener.at(i)->handleUpdate();
}
}
void write(std::string value) {
std::cout << "Write 1" << std::endl;
string = &value;
handleCommand();
}
private:
std::string *string;
};
class MyListener : public Listener {
public:
MyListener(int num) : num(num) {
};
~MyListener() {
}
void handleUpdate() {
std::cout << "Listener " << num << " with string " << *string << std::endl;
}
private:
int num;
};
class CommandManager {
public:
void publish(std::string name, std::string value) {
std::map<std::string, boost::shared_ptr<Command> >::iterator it;
it = commandMap.find(name);
if (it == commandMap.end()) {
// add a new one
boost::shared_ptr<Command> command(new Command());
commandMap[name] = command;
}
it = commandMap.find(name);
it->second->write(value);
}
void subscribe(std::string name, boost::shared_ptr<Listener> l) {
std::map<std::string, boost::shared_ptr<Command> >::iterator it;
it = commandMap.find(name);
if (it == commandMap.end()) {
boost::shared_ptr<Command> command(new Command());
command->setListener(l);
commandMap[name] = command;
} else {
it->second->setListener(l);
}
}
private:
std::map<std::string, boost::shared_ptr<Command> > commandMap;
};
int main(int argc, char** argv) {
boost::shared_ptr<MyListener> myListener0(new MyListener(0));
boost::shared_ptr<MyListener> myListener1(new MyListener(1));
boost::shared_ptr<MyListener> myListener2(new MyListener(2));
CommandManager commandManager;
commandManager.subscribe("Tyler", myListener0);
commandManager.subscribe("Tyler", myListener1);
commandManager.subscribe("Tyler", myListener2);
commandManager.publish("Tyler", " is cool");
return 0;
}
#包括
#包括
#包括
#包括
#包括
类侦听器{
公众:
虚拟void handleUpdate()=0;
std::string*string;
};
类命令{
向量监听器;
公众:
~Command(){
}
void setListener(boost::shared_ptr l){
监听器。推回(l);
}
void handleCommand(){
对于(int i=0;i //std::coutCommandManager
是否拥有传递给它的指针ttl.get()
(即它是否删除它)?@hmjdCommandManager
不拥有所有权,Command
类拥有所有权,并且在超出范围时尝试删除它。为什么Command要删除它不拥有的东西?你需要决定谁拥有指针。@hmjd所以你说Command
不能包含m_listener
的副本,但是m>怎么能_监听器的handleUpdate()
方法被调用?有什么想法吗?CommandManager
是否拥有传递给它的指针ttl.get()
(即它是否删除它)?@hmjdCommandManager
不拥有所有权,Command
类拥有所有权,并在超出范围时尝试将其删除。为什么Command要删除