繁体   English   中英

赛格。 std :: unique_ptr和ctor错误

[英]Seg. fault with std::unique_ptr and ctor

对于解析器,我实际上正在实现,我在解析器中部分地拥有这些私有函数:

解析器私有方法:

    Token const* current_token() const;
    Token const* next_token();
    Token const* peek_token();

    std::unique_ptr<ast::Expression> parse_expression();
    std::unique_ptr<ast::TypeSpecifier> parse_type_specifier();
    std::unique_ptr<ast::VariableDeclarationStatement> parse_variable_declaration();
    std::unique_ptr<ast::Statement> parse_function_definition();
    std::unique_ptr<ast::Statement> parse_top_level_statement();

parse_variable_declaration方法的实现是这样的:

parse_variable_declaration():

std::unique_ptr<ast::VariableDeclarationStatement> Parser::parse_variable_declaration() {
    next_token(); // consume 'var'

    if (current_token()->get_type() != TokenTypes::identifier) {
        throw parser_error(current_token(), "", "expected identifier\n");
    }
    const auto id = current_token(); // store identifier
    next_token(); // consume identifier

    std::unique_ptr<ast::TypeSpecifier> type;
    std::unique_ptr<ast::Expression> expr;

    auto assignment_required = true;
    if (current_token()->get_type() == TokenTypes::op_colon) { // optional type specifier
        next_token(); // consume ':'

        type = parse_type_specifier();
        assignment_required = false;
    }

    if (assignment_required && current_token()->get_type() != TokenTypes::op_equals) {
        throw parser_error(current_token(), "", "expected equals operator\n");
    }

    if (current_token()->get_type() == TokenTypes::op_equals) {
        next_token(); // consume '='

        expr = parse_expression();
    }

    if (current_token()->get_type() != TokenTypes::op_semi_colon) {
        throw parser_error(current_token(), "", "expected semi-colon\n");
    }

    next_token(); // consume ';'

    DEBUG_STDERR("parsed: variable_declaration_statement\n");
    return std::make_unique<ast::VariableDeclarationStatement>(
        id->get_string(), std::move(type), std::move(expr));
}

最后一行(返回)以分段错误结束。 它基本上会调用VariableDeclarationStatement的构造函数:

VariableDeclarationStatement ctor:

VariableDeclarationStatement::VariableDeclarationStatement(
    std::string const& name,
    std::unique_ptr<TypeSpecifier> type_specifier,
    std::unique_ptr<Expression> expr
):
    m_name{name},
    m_type_specifier{std::move(type_specifier)},
    m_expr{std::move(expr)}
{}

自昨天以来,我一直在调试这些东西,似乎无法找出为什么这不能按预期进行。 我想用指向其子节点的唯一指针来构建抽象语法树(解析器输出)(因为它们是有意义的子节点的唯一所有者)-这就是为什么我努力尝试与它们一起工作的原因。

控制台输出:DEBUG_STDERR

parsed: primitive_type_int // from parse_type_specifier()
parsed: integral_expression // from parse_expression()
parsed: variable_declaration_statement
[1]    12638 segmentation fault (core dumped)  ./cion_compiler

唯一指针的移动操作基本上可以归结为简单的指针副本。 没有任何理由可以使unique_ptr任何实现在移动它们的过程中取消引用指针。 因此,此操作导致段错误的可能性实际上为零。

在return-statement / constructor-call中,您确实有一个(或多个)非常明显的指针取消引用,这是id->get_string()调用的一部分。

首先, id指针的创建方式如下:

  const Token* const id = current_token(); // store identifier
  next_token(); // consume identifier

除非能够保证current_token()返回的任何指针在时间结束之前(或在当前解析操作的生命周期内current_token()都有效,否则很有可能在调用next_token()id指针无效,即指向不存在或已失效的Token对象。

即使id指针仍然指向现有的Token对象,它也可能处于“僵尸”状态,并且通过get_string()从中获取字符串是无效的操作。

如果我是你,那将是我寻找段错误的来源。 您可能还想在(内存-)调试器中运行它来获取其源代码,它可能会将您指向get_string函数作为其源代码,无论是在this指针( id指针)的取消引用期间。或在琴弦本身的构造过程中。 如果get_stringToken类中的虚拟函数,它也可能将您引向虚拟表查找。 无论哪种方式,我都高度怀疑这是段错误的原因,因为它是您所发布内容中唯一公开的危险代码。

如您所愿,错误被隐藏在可疑的id指针中。 我程序中的解析器通过词法分析器通过unique_ptr接收令牌,并将其作为当前令牌正确存储。 因此,方法current_token()返回了一个指向unique_ptr的指针,该指针将在下次调用next_token()时立即删除。 在id中存储指向已删除的令牌的无效指针会导致此问题。

我以几种不同的方式修复了代码。

首先,我将上述帮助方法的返回类型从“ Token const *”更改为“ Token const&”,并且id变量现在仅复制get_string值,并且不执行其他与指针相关的操作。

通过这些更改,成功解决了分割错误问题! =)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM