Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从C`goto`错误处理范式过渡到C++;异常处理范例 我是一个学习C++的C程序员。在C语言中,有一个共同点。通过代码>我读过异常处理,尝试 >代码> catch >代码>在面向对象程序中是首选的,但是在C++中实现这个范例有困难。_C++_C_Exception_Error Handling_Exception Handling - Fatal编程技术网

从C`goto`错误处理范式过渡到C++;异常处理范例 我是一个学习C++的C程序员。在C语言中,有一个共同点。通过代码>我读过异常处理,尝试 >代码> catch >代码>在面向对象程序中是首选的,但是在C++中实现这个范例有困难。

从C`goto`错误处理范式过渡到C++;异常处理范例 我是一个学习C++的C程序员。在C语言中,有一个共同点。通过代码>我读过异常处理,尝试 >代码> catch >代码>在面向对象程序中是首选的,但是在C++中实现这个范例有困难。,c++,c,exception,error-handling,exception-handling,C++,C,Exception,Error Handling,Exception Handling,以C语言中使用goto错误处理范例的以下函数为例: unsigned foobar(void){ 文件*fp=fopen(“blah.txt”、“r”); 如果(!fp){ 转到福彭出口; } /*blackbox函数执行各种操作 *上的操作,并以其他方式修改, *外部数据结构的状态*/ if(blackbox()){ 转到黑匣子出口; } 常数大小数值基准=42; 无符号long*data=malloc(NUM_DATUM*sizeof(*data)); 如果(!数据){ 转到退出_数据; }

以C语言中使用
goto
错误处理范例的以下函数为例:

unsigned foobar(void){
文件*fp=fopen(“blah.txt”、“r”);
如果(!fp){
转到福彭出口;
}
/*blackbox函数执行各种操作
*上的操作,并以其他方式修改,
*外部数据结构的状态*/
if(blackbox()){
转到黑匣子出口;
}
常数大小数值基准=42;
无符号long*data=malloc(NUM_DATUM*sizeof(*data));
如果(!数据){
转到退出_数据;
}
对于(大小i=0;i

我尝试用异常处理范式重新创建C++中的函数:

unsigned foobar(){
ifstream fp(“blah.txt”);
如果(!fp.is_open()){
返回1;
}
试一试{
//blackbox函数执行各种操作
//上的操作,并以其他方式修改,
//外部数据结构的状态
黑盒();
}捕获(…){
fp.close();
返回1;
}
常数大小数值基准=42;
无符号长*数据;
试一试{
数据=新的无符号长[NUM_DATUM];
}捕获(…){
//undo_blackbox函数恢复
//blackbox函数所做的更改
撤销_黑匣子();
fp.close();
返回1;
}
对于(大小i=0;i>数据[i];
}
对于(尺寸i=0;i
这意味着您可以创建一个本地RAII管理器,当它超出范围时,它将自动清理它正在管理的任何东西,无论是由于正常的程序流还是异常引起的。永远不应该仅仅为了清理而需要
catch
块;只有当您需要处理或报告异常时才需要

在您的案例中,您有三种资源:

  • 文件
    fp
    ifstream
    已经是RAII类型,所以只需删除对
    fp.close()
    的冗余调用,一切都很好
  • 分配的内存
    data
    。如果它是一个小的固定大小(就是这样),则使用本地数组;如果需要动态分配,则使用
    std::vector
    ;然后去掉
    删除
  • blackbox
    设置的状态
您可以为“黑盒”malarkey编写自己的RAII包装:

struct blackbox_guard {
    // Set up the state on construction
    blackbox_guard()  {blackbox();}

    // Restore the state on destruction
    ~blackbox_guard() {undo_blackbox();}

    // Prevent copying per the Rule of Three
    blackbox_guard(blackbox_guard const &) = delete;
    void operator=(blackbox_guard) = delete;
};
现在,您可以删除所有错误处理代码;我希望通过异常(抛出或允许传播)来指示失败,而不是一个神奇的返回值,给出:

void foobar(){
    ifstream fp ("blah.txt"); // No need to check now, the first read will fail if not open
    blackbox_guard bb;

    const size_t NUM_DATUM = 42;
    unsigned long data[NUM_DATUM];   // or vector<unsigned long> data(NUM_DATUM);

    for(size_t i = 0; i < NUM_DATUM; i++){
        string buffer;

        // You could avoid this check by setting the file to throw on error
        // fp.exceptions(ios::badbit); or something like that before the loop
        if(!getline(fp, buffer)){
             throw std::runtime_error("Failed to read"); // or whatever
        }

        stringstream(buffer) >> data[i]; // or data[i] = stoul(buffer);
    }

    for(size_t i = 0; i < NUM_DATUM/2; i++){
        cout << data[i] + data[i + NUM_DATUM/2] << endl;
    }
}
void foobar(){
ifstream fp(“blah.txt”);//现在无需检查,如果未打开,第一次读取将失败
黑盒保护bb;
常数大小数值基准=42;
无符号长数据[NUM_DATUM];//或向量数据(NUM_DATUM);
对于(大小i=0;i>data[i];//或data[i]=stoul(buffer);
}
对于(尺寸i=0;i
核心思想是在初始化对象的过程中获取资源,并设置对象,使其在销毁时正确释放资源。这一工作的关键点是,当通过异常退出作用域时,析构函数正常运行

在您的情况下,已经有RAII可用,您只是没有使用它。
std::ifstream
(我假设这就是您的
ifstream
所指的)确实会在销毁时关闭。因此可以安全地忽略
catch
中的所有
close()

对于
数据
,您也应该使用RAII包装。有两种可用:
std::unique_ptr
,和
std::vector
。它们都负责各自析构函数中的内存释放

最后,对于
blackbox()
,您可以自己创建一个简单的RAII包装器:

struct BlackBoxer
{
  BlackBoxer()
  {
    blackbox();
  }

  ~BlackBoxer()
  {
    undo_blackbox();
  }
};
当使用这些代码重写时,您的代码将变得更加简单:

unsigned foobar() {
  ifstream fp ("blah.txt");
  if(!fp.is_open()){
    return 1;
  }

  try {
    BlackBoxer b;

    const size_t NUM_DATUM = 42;
    std::vector<unsigned long> data(NUM_DATUM);
    for(size_t i = 0; i < NUM_DATUM; i++){
      string buffer;
      if(!getline(fp, buffer)){
        return 1;
      }

      stringstream(buffer) >> data[i];
    }

    for(size_t i = 0; i < NUM_DATUM/2; i++){
      cout << data[i] + data[i + NUM_DATUM/2] << endl;
    }

    return 0;
  } catch (...) {
    return 1;
  }
}
unsigned foobar(){
ifstream fp(“blah.txt”);
如果(!fp.is_open()){
返回1;
}
试一试{
黑盒b;
常数大小数值基准=42;
std::矢量数据(NUM_数据);
对于(大小i=0;i>数据[i];
}
// void return type, we may no guarantees about exceptions
// this function may throw
void foobar(){
   // the blackbox function performs various
   // operations on, and otherwise modifies,
   // the state of external data structures
   blackbox();

   // scope exit will cleanup blackbox no matter what happens
   // a scope exit like this one should always be used
   // immediately after the resource that it is guarding is
   // taken.
   // but if you find yourself using this in multiple places
   // wrapping blackbox in a dedicated wrapper is a good idea
   BOOST_SCOPE_EXIT[]{
       undo_blackbox();
   }BOOST_SCOPE_EXIT_END


   const size_t NUM_DATUM = 42;
   // using a vector the data will always be freed
   std::vector<unsigned long> data;
   // prevent multiple allocations by reserving what we expect to use
   data.reserve(NUM_DATUM);
   unsigned long d;
   size_t count = 0;
   // never declare things before you're just about to use them
   // doing so means paying no cost for construction and
   // destruction if something above fails
   ifstream fp ("blah.txt");
   // no need for a stringstream we can check to see if the
   // file open succeeded and if the operation succeeded
   // by just getting the truthy answer from the input operation
   while(fp >> d && count < NUM_DATUM)
   {
       // places the item at the back of the vector directly
       // this may also expand the vector but we have already
       // reserved the space so that shouldn't happen
       data.emplace_back(d);
       ++count;
   }

   for(size_t i = 0; i < NUM_DATUM/2; i++){
       cout << data[i] + data[i + NUM_DATUM/2] << endl;
   }
}
#include <fstream>
#include <stdexcept>
#include <vector>

// C or low-level functions to be wrapped:
int blackbox();
void undo_blackbox();

// just to be able to compile this example:
FILE *fp;

// The only self-made RAII class we need for this example
struct Blackbox {
    Blackbox() {
        if (!blackbox()) {
            throw std::runtime_error("blackbox failed");
        }
    }

    // Destructor performs cleanup:
    ~Blackbox() {
        undo_blackbox();
    }   
};

void foobar(void){
    // std::ifstream is an implementation of the RAII idiom,
    // because its destructor closes the file:
    std::ifstream is("blah.txt");
    if (!is) {
        throw std::runtime_error("could not open blah.txt");
    }

    Blackbox local_blackbox;

    // std::vector itself is an implementation of the RAII idiom,
    // because its destructor frees any allocated data:
    std::vector<unsigned long> data(42);

    for(size_t i = 0; i < data.size(); i++){
        char buffer[256] = "";
        if(!fgets(buffer, sizeof(buffer), fp)){
            throw std::runtime_error("fgets error");
        }

        data[i] = strtoul(buffer, NULL, 0);
    }

    for(size_t i = 0; i < (data.size()/2); i++){
        printf("%lu\n", data[i] + data[i + (data.size()/2)]);
    }

    // nothing to do here - the destructors do all the work!
}