【问题标题】:Odd behavior after adding exceptions添加异常后的奇怪行为
【发布时间】:2019-08-12 22:27:30
【问题描述】:

我在我的项目中的一些函数中添加了一些异常处理。在添加错误处理之前,程序运行正常。添加异常后,我现在在构造函数和 mutator 参数中得到垃圾值,我不确定它来自哪里。有些函数在构造函数之外没有其他位置被调用,所以我不知道它们从哪里获取垃圾数据。

我还使用 valgrind 检查了内存泄漏并使用 gdb 进行了一些调试,但没有找到任何东西。我无计可施。我在下面附上了构造函数 cpp 的示例以及具有异常处理的突变器之一。

Protofield.cpp

ProtoField::ProtoField(std::string t_name, std::string t_abbreviation, FieldType t_type, Base t_base, int t_mask, std::string t_description, int t_offset, int t_length){
    try{
        setName(t_name);
        setAbbreviation(t_abbreviation);
        setType(t_type);
        setBase(t_base);
        setMask(t_mask);
        setDescription(t_description);
        setOffset(t_offset);
        setLength(t_length);
        m_valueString = std::map<int, std::string>();
    }
    catch(std::runtime_error e){
        std::cerr<<"Error in ProtoField Constructor"<<std::endl;
        std::cerr<<e.what()<<std::endl;
        return;
    }
}
/*Removed for brevity*/
void ProtoField::setMask(int t_mask){
    if(mask != 0){
        std::stringstream ss;
        ss<<"Field " << m_abbreviation << " mask previously set: "<<m_mask;
        throw std::runtime_error(ss.str());
    }
    else{
        m_mask = t_mask;
    }
    return;
}
/*Removed for brevity*/

ProtoField.hpp

class ProtoField{
    private:
        std::string m_name;
        std::string m_abbreviation;
        FieldType m_type;
        Base m_base;
        int m_mask;
        std::string m_description;
        int m_offset;
        int m_length;
        std::map<int, std::string> m_valueString;
    public:
        ProtoField(
            std::string t_name = "",
            std::string t_abbreviation = "",
            FieldType t_type = FieldType::ft_invalid,
            Base t_base = Base::invalid,
            int t_mask = 0,
            std::string t_description = "", 
            int t_offset = -1,
            int t_length = -1
        );

        std::string getName();
        std::string getAbbreviation();
        FieldType getType();
        Base getBase();
        int getMask();
        std::string getDescription();
        int getOffset();
        int getLength();
        std::map<int, std::string> getValueString();

        void setName(std::string t_name);
        void setAbbreviation(std::string t_abbreviation);
        void setType(FieldType t_type);
        void setType(std::string t_typestr);
        void setBase(Base t_base);
        void setBase(std::string t_basestr);
        void setMask(int t_mask);
        void setDescription(std::string t_description);
        void setOffset(int t_offset);
        void setLength(int t_length);
        void addValueString(int t_key, std::string t_value);
        void removeValueString(int t_key);

        //other functions
        std::string to_string();
    };

我觉得它也值得一提,似乎只有整数受到影响。包括字符串和枚举在内的其他值似乎与它们之前的行为保持一致。所以在显示的类中,只有掩码、偏移量和长度显示出奇怪的行为。

编辑:关于调用构造函数的更多细节,我在这里包含了我知道的两个函数。

void parser::parseFields(ProtoData& t_data, ptree::ptree t_subtree){
        try{
            std::vector<ProtoField> fields;
            for(auto val : t_subtree.get_child("")){
                ProtoField field;
                parseField(t_data, field, val.second);
                fields.push_back(field);
            }
            for(auto field:fields){
                t_data.addField(field);
            }
        }
        catch(ptree::ptree_bad_path error){
            std::cerr<<"Bad Path to Fields"<<std::endl;
        }
        catch(ptree::ptree_bad_data error){
            std::cerr<<"Bad Data to fields"<<std::endl;
        }
    }

    void parser::parseField(ProtoData& t_data, ProtoField& t_field, ptree::ptree t_subtree){
        try{
            t_field.setAbbreviation(t_subtree.get<std::string>("abbreviation"));
            t_field.setName(t_data.getName() + "_" + t_field.getAbbreviation());
            t_field.setBase(t_subtree.get<std::string>("base", "none"));
            t_field.setType(t_subtree.get<std::string>("type"));
        }
        catch(ptree::ptree_bad_path error){
            std::cerr<<"Bad Path to Field"<<std::endl;
        }
        catch(ptree::ptree_bad_data error){
            std::cerr<<"Bad Data to field"<<std::endl;
        }
    }

【问题讨论】:

  • 在您的测试中是否抛出了任何异常?
  • catch(std::runtime_error e) -- 你应该通过引用而不是值来捕获异常。另外,为什么已经存在的面具是例外情况?在 C++ 中,应该为那些异常情况保留异常,即已经发生的事情应该永远发生,但它确实发生了。
  • @MrErivSir:除了我描述的行为之外,没有什么。我有一个使用 boost 的单独的单元测试可执行文件,它只报告我刚刚编写的异常。
  • 请发帖minimal reproducible example。我们不知道您创建 ProtoField 实例的方式、地点或时间。仅仅发布一个类和标题不足以确定发生了什么——我们需要看到类“正在运行”,即你正在做什么来触发错误。
  • std::vector&lt;ProtoField&gt; -- 在您的ProtoField 中,FieldType 是什么? Base 是什么?意识到std::vector 进行复制,因此您的ProtoField 需要具有正确的复制语义。

标签: c++ c++11 exception


【解决方案1】:

您的构造函数没有初始化m_mask。然后调用setMask,它读取这个尚未初始化的值(假设if(mask != 0) 行应该是if(m_mask != 0))。这是未定义的行为。读取的值可以是任何值。当为非零值时,会抛出异常。

解决方法是要么在调用setMask之前初始化m_mask,要么在构造函数中直接赋值给m_mask而不调用辅助函数。 (而且既然构造函数设置了掩码,只能做一次,那这个函数为什么还要存在呢?)

【讨论】:

    猜你喜欢
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2014-05-25
    • 2013-10-24
    • 2014-01-21
    • 1970-01-01
    • 2017-09-05
    • 1970-01-01
    相关资源
    最近更新 更多