【问题标题】:Seg. fault with std::unique_ptr and ctor赛格。 std::unique_ptr 和 ctor 出现故障
【发布时间】:2015-02-09 02:59:17
【问题描述】:

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

解析器私有方法:

    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

【问题讨论】:

  • 你不能在调试器下运行吗?如果你这样做,应该很容易追踪发生了什么。以及你如何使用Parser::parse_variable_declaration() 的返回值可能也很重要。
  • 为什么ctor参数不是std::unique_ptr&lt;TypeSpecifier&gt; &amp;&amp;type_specifier
  • 我想知道您是否可以创建一个small, complete program 来重现您有问题的return 声明。否则,您只是希望问题的根源恰好在您选择向我们展示的代码中。
  • @Slava 为什么会这样?它是一个 sink 参数,当前的签名清楚地表明构造函数无条件地接管了参数。
  • @Praetorian 我认为当参数是右值引用时,很明显构造函数会移动参数,不是吗?

标签: c++ segmentation-fault smart-pointers move-semantics unique-ptr


【解决方案1】:

对唯一指针的移动操作基本上可以归结为简单的指针副本。 unique_ptr 的任何实现都没有理由在移动指针的过程中取消引用指针。因此,此操作导致 seg-fault 的可能性几乎为零。

在您的返回语句/构造函数调用中,您确实有一个(或多个)非常明显的指针取消引用,作为id-&gt;get_string() 调用的一部分。

首先,id 指针是这样创建的:

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

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

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

如果我是你,我会在那里寻找 seg-fault 的根源。您可能还想在(内存)调试器中运行它以获取它的源,它可能会将您指向 get_string 函数作为它的源,或者在取消引用 this 指针期间( id 指针)或在字符串本身的构造过程中。如果get_stringToken 类中的虚函数,它还可以将您指向虚拟表查找。无论哪种方式,我都高度怀疑这是 seg-fault 的原因,因为它是您发布的内容中唯一明显危险的代码。

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-23
      • 2012-12-08
      • 2018-04-19
      相关资源
      最近更新 更多