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::cout
CommandManager
是否拥有传递给它的指针
ttl.get()
(即它是否
删除它)?@hmjd
CommandManager
不拥有所有权,
Command
类拥有所有权,并且在超出范围时尝试删除它。为什么Command要删除它不拥有的东西?你需要决定谁拥有指针。@hmjd所以你说
Command
不能包含
m_listener
的副本,但是
m>怎么能_监听器的
handleUpdate()
方法被调用?有什么想法吗?
CommandManager
是否拥有传递给它的指针
ttl.get()
(即它是否
删除它)?@hmjd
CommandManager
不拥有所有权,
Command
类拥有所有权,并在超出范围时尝试将其删除。为什么Command要删除