【问题标题】:Exception handling in Protocol Buffers C++协议缓冲区 C++ 中的异常处理
【发布时间】:2015-04-15 02:28:01
【问题描述】:

我在 Protocol Buffers 文档中没有找到任何关于 C++ 异常处理的内容。在 Javadoc 中明确定义了 InvalidProtocolBufferException,但在 C++ 中没有。

有时我运行我的程序,当它发现它认为有效消息中的缺失字段时它会崩溃,然后它会停止并抛出如下错误:

[libprotobuf FATAL google/protobuf/message_lite.cc:273] CHECK failed: 
IsInitialized(): Can't serialize message of type "XXX" because it is 
missing required fields: YY, ZZ
unknown file: Failure
C++ exception with description "CHECK failed: IsInitialized(): Can't 
serialize message of type "XXX" because it is missing required fields: 
YY, ZZ" thrown in the test body.

message_lite.cc 的source code 全部用“GOOGLE_DCHECK”或“InitializationErrorMessage”包裹...

我的应用程序不允许这样的异常来停止程序(不确定 C++ 中的术语是什么,但基本上没有 UncheckedExceptions),所以我真的需要一种方法来捕获这些异常,记录错误并优雅地返回,以防万一消息被严重损坏。反正有这样做吗?为什么我看到 this post 表示某种 google::protobuf::FatalException 但我找不到它周围的文档(只有 FatalException 可能也不够)。

谢谢!

【问题讨论】:

    标签: c++ exception exception-handling protocol-buffers


    【解决方案1】:

    您看到的失败表明您的程序中存在错误 - 程序已请求序列化消息而没有先填写所有必填字段。将此视为分段错误。您不应该尝试捕获此异常 - 您应该修复您的应用,以便从一开始就不会发生异常。

    请注意,检查是DCHECK,这意味着它仅在调试版本中检查。在您的发布版本中(定义 NDEBUG 时),将跳过此检查并写入消息,即使它无效。因此,您不必担心这会使您的应用程序在生产中崩溃,只需在调试时即可。

    (从技术上讲,您可以捕获 google::protobuf::FatalException,但 Protobuf 代码最初并不是为异常安全而设计的。最初,检查失败只会中止程序。看起来 FatalException 是最近添加的,但由于代码不是异常安全的,任何时候抛出 FatalException 都可能导致内存泄漏。因此,您可能应该像对待 abort() 一样对待它。)

    【讨论】:

    • 谢谢!还有一个问题,Protobuf 如何识别自己是处于生产模式还是调试模式?就我而言,是因为我将它与 Google Test 一起使用,所以它会自动找出它是 DEBUG 吗? “没有例外”的交易听起来很公平,因为我猜这是为了与正常的 Java 与 C++ 约定保持一致?因为所有这些“InvalidBufferException”的东西都被建模为异常,如果它在 Java 中,但也许它是预期的,就像你在 Java 中不能有段错误一样......
    • @Superziyi 如果使用NDEBUG#defined 编译protobufs,则它处于发布模式,否则处于调试模式(NDEBUG = 非调试)。如果您使用的是 unix 并且使用常规的 configure、make、make install 来构建 protobuf,则默认情况下它应该处于发布模式(您可以在运行 configure 时通过设置 CXXFLAGS 来覆盖)。如果您在 Windows 上,MSVC 通常在发布配置中 #defines NDEBUG。 (NDEBUG 宏是标准的 C-ism。)
    【解决方案2】:

    我解决了 我的问题和你一样。 如果在您进行序列化时另一个线程更改了原型项目的大小,则 FatalException 抛出 然后首先我将其复制到另一个原型项目中,然后我将其序列化。

                ProtoInput item; // it is global object
                . 
                .
                .
                fstream output("myfile",
                        ios::out | ios::trunc | ios::binary);
    
                ProtoInput in;
                in.CopyFrom(item);
                size_t size = in.ByteSizeLong();
                void *buffer = malloc(size);
                if (in.SerializeToArray(buffer, size) == true) {
                    output.write((char *) buffer, size);
                }
                output.close();
                free(buffer);
    

    【讨论】:

      猜你喜欢
      • 2011-09-18
      • 2021-12-19
      • 1970-01-01
      • 2011-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多