簡體   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