草庐IT

c++ - 在回调函数中安全地删除调用者对象

coder 2024-02-05 原文

库中的代码段:

class Client{
public:
    class CallBack {
    public:
        virtual void onData(Client* caller, std::string& data) =0;
    };

    Client(CallBack* callback):m_callBack(callback){}
    virtual ~Client(){}
    void onData(std::string data) {
        m_callBack->onData(this, data);
        m_totalDataVol += data.size();
    }

private:
    CallBack* m_callBack;
    int m_totalDataVol = 0;
}

来自应用程序的代码段:

class AppHandler: public Client::Callback {
    void onData(Client* caller, std::string& data) {
        /* Some complex logic and check certain conditions*/
            delete caller; // Application will crash, due to 
                           // accessing member of deleted object (m_totalDataVol)
    }
}

此外Caller对象(Client类的实例)为应用程序所有,应用程序没有限制删除它。

我该如何克服这个问题?

非常复杂的场景: 基础库的 Client 类可以由另一个库(ClientEx 类)扩展,应用程序可能会使用该扩展库(不是基础库)

最佳答案

让你的回调返回一个 bool 指示调用者是否应该删除自己。不要从回调中删除客户端。

此外,如果 data.size == 0,是否还需要调用回调? Client 可以在调用回调之前检查此条件,并删除自身(或以其他方式适本地处理它)。

如果仍然需要调用回调,也许您可​​以通过在调用后检查客户端中的条件来避免更改返回类型:

void onData(std::string data) {
    m_callBack->onData(this, data);
    if (data.size() != 0) {
        m_totalDataVol += data.size();
    }
    else {
        delete this;
    }
}

或者,如果您真的必须允许回调来删除客户端,那么您需要某种方式来跟踪客户端何时被删除,您可以在客户端本身中使用这种方式。这意味着保留对另一个对象的引用:

class Client{
public:
    class CallBack {
    public:
        virtual void onData(Client* caller, std::string& data) =0;
    };

    Client(CallBack* callback):m_callBack(callback){}, was_deleted(nullptr)
    virtual ~Client(){
        if (was_deleted) *was_deleted = true;
    }
    void onData(std::string data) {
        bool *was_deleted = new bool();
        this->was_deleted = was_deleted;
        m_callBack->onData(this, data);
        if (! *was_deleted) {
            m_totalDataVol += data.size();
            this->was_deleted = nullptr;
        }
        delete was_deleted;
    }

private:
    CallBack* m_callBack;
    int m_totalDataVol = 0;
    // When issuing a callback, holds a pointer to a flag that can
    // be used to track if this object has been deleted:
    bool * was_deleted;
}

(请注意,上面的解决方案不是线程安全的,但可能会如此。另请注意,上面的代码无法编译,就像您问题中的示例代码一样 - 我已经尝试匹配源代码尽可能多,原则应适用于实际代码)。

关于c++ - 在回调函数中安全地删除调用者对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32472221/

有关c++ - 在回调函数中安全地删除调用者对象的更多相关文章

  1. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  2. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  5. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  6. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  7. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  8. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  9. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  10. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

随机推荐