C++ 如果引入 try-catch,则出现分段错误

C++ Segmentation fault if try-catch is introduced

本文关键字:分段 错误 如果 try-catch C++      更新时间:2023-10-16

我正在使用boost::interprocess运行最简单的进程间通信程序设置:

#include <boost/interprocess/managed_shared_memory.hpp>
#include <cstdlib> //system
#include <iostream>
using namespace std;
using namespace boost::interprocess;
typedef pair<double, int> MyType;
int main(int argc, char *argv[]) {
    if (argc==1) {  //Parent process
        struct shm_remove {
            shm_remove() {shared_memory_object::remove("MySharedMemory");}
            ~shm_remove() {shared_memory_object::remove("MySharedMemory");}
        } remover;
        managed_shared_memory segment(create_only,"MySharedMemory",65536);
        MyType* instance=segment.construct<MyType>("MyType instance")(0.5,2);
        string s(argv[0]);
        s+=" child ";
        if(system(s.c_str())!=0) {
            cout<<"Parent: Child process returned non-zero"<<endl;
            return 1;
        }
        cout<<"Parent: Child process finished successfully"<<endl;
        segment.destroy<MyType>("MyType instance");
    } else { //Child process
        pair<MyType*, managed_shared_memory::size_type> res;
//        try {
            managed_shared_memory segment(open_only, "MySharedMemory");
            res=segment.find<MyType>("MyType instance");
//        } catch (interprocess_exception &e) {
//            cerr<<"Error while opening the segment"<<endl;
//            return 1;
//        }
        cout<<"Child: Segment of length "<<res.second<<" is found at "<<res.first<<endl;
        cout<<"Child: "<<res.first->first<<", "<<res.first->second<<endl;
    }
    return 0;
}

这有效,我看到:

Child: Segment of length 1 is found at 0x106a15148
Child: 0.5, 2
Parent: Child process finished successfully

但是,当我取消注释try-catch块时,我看到以下内容:

Child: Segment of length 1 is found at 0x10a8fd148
Parent: Child process returned non-zero

如果我将二进制文件一分为二(段生成和永久休眠的父级和段读取的子级),它再次在没有try-cacth的情况下工作,但有了它,子级崩溃了

Segmentation fault: 11

因此,我有两个问题:

  1. 引入try-catch会导致什么?它的行为就像块有自己的地址空间一样。但为什么会这样呢?
  2. 如何安全地检查所需段是否存在并生成找不到的错误消息?

编辑:

我已将块更改为:

if (1) {
    managed_shared_memory segment(open_only, "MySharedMemory");
    res=segment.find<MyType>("MyType instance");
    cout<<"Child: Segment of length "<<res.second<<" is found at "<<res.first<<endl;
    cout<<"Child: "<<res.first->first<<", "<<res.first->second<<endl;
}

我收到同样的错误:

Child: Segment of length 1 is found at 0x108c15148
Child: 0.5, 2
Child: Segment of length 1 is found at 0x108c15148
Parent: Child process returned non-zero

所以,这种行为确实是{}造成的,大概是segment的破坏。但是,如果res.first已经填充了正确的指针,为什么会很重要呢?

问题似乎是调用了 managed_shared_memory 的析构函数,但您在 try catch 块之后继续依赖它持有的状态或分配。

managed_shared_memory segment;

回想一下,析构函数总是在作用域的末尾调用(基本上是任何关闭}),这也适用于 try 块。

如果这不是"main"函数,最好让异常转义给调用者(no try catch),或者重新抛出它(或其他异常):

    try {
        managed_shared_memory segment(open_only, "MySharedMemory");
        res=segment.find<MyType>("MyType instance");
        cout<<"Child: Segment of length "<<res.second<<" is found at "<<res.first<<endl;
        cout<<"Child: "<<res.first->first<<", "<<res.first->second<<endl;
    } catch (interprocess_exception &e) {
        cerr<<"Error while opening the segment"<<endl;
        throw;
    }

确实,请查看文档

托管内存段最重要的服务包括:

  • 动态分配段内存的各个部分。

  • 在内存段中构造C++对象。这些对象可以是匿名的,或者我们可以将名称与它们相关联。

  • 命名对象的搜索功能。

  • 许多功能的定制:内存分配算法,索引类型或字符类型。

  • 原子构造和破坏,因此如果段在两个进程之间共享,则无法创建两个对象
    与同名关联,简化同步。