c++ - std::vector.push_back() 抛出 badalloc 异常

标签 c++ exception vector stdvector

我开始编写词法分析器,并制作了以下文件来测试到目前为止一切正常:

main.cpp

#include <iostream>
#include "Lexer.h"
#include "Token.h"

int main(void)
{
    std::string str(""); // I'll use this to test expressions
    Lexer lexer(str);
    std::vector<Token> tokens = lexer.lex();
    for(auto it = tokens.begin(); it != tokens.end(); ++it)
    {
        std::string str;
        switch(it->type)
        {
        case TokenType::_EOF:
            str = "EOF";
            break;
        case TokenType::ERROR:
            str = "ERROR";
            break;
        case TokenType::SEMICOLON:
            str = "SEMICOLON";
            break;
        case TokenType::PLUS:
            str = "PLUS";
            break;
        case TokenType::LESS_THAN:
            str = "LESS_THAN";
            break;
        case TokenType::GREATER_THAN:
            str = "GREATER_THAN";
            break;
        case TokenType::INT:
            str = "INT";
            break;
        case TokenType::ID:
            str = "ID";
            break;
        case TokenType::WHITESPACE:
            str = "WHITESPACE";
            break;
        default:
            str = "<Unknown Token>";
        }
        std::cout << str << ", detail='" << it->detail << "'" << std::endl;
    }
    return 0;
}

lexer.lex() 行抛出异常。查看 Lexer.h:

std::vector<Token> Lexer::lex(void)
{
    // Reset input pointer
    inputPtr = 0;
    updateCurrentChar();
    // Read tokens until EOF
    std::vector<Token> tokens;
    Token *token = nullptr;
    do
    {
        token = getNext();
        tokens.push_back(*token);
    } while(token->type != TokenType::_EOF);
    return tokens;
}

tokens.push_back(*token) 行抛出异常:

Exception details

我试着查看有关 push_back() 的信息 here ,并看到:

If a reallocation happens, the storage is allocated using the container's allocator, which may throw exceptions on failure (for the default allocator, bad_alloc is thrown if the allocation request does not succeed).

这似乎是我的问题,但我不明白为什么分配请求不会成功。

为了完整起见,这里是所有文件:

token .h

#pragma once
#include <string>

enum class TokenType
{
    _EOF,
    ERROR,
    EQUALS,
    SEMICOLON,
    PLUS,
    LESS_THAN,
    GREATER_THAN,
    INT,
    ID,
    WHITESPACE
};

struct Token
{
    TokenType type;
    std::string detail;
};

词法分析器.h

#pragma once
#include <string>
#include <vector>
#include "Token.h"

class Lexer
{
public:
    Lexer(std::string);
    ~Lexer(void);
    std::vector<Token> lex(void);
private:
    Token* getNext(void);
    void updateCurrentChar(void);
    void increment(void);
    bool matchCurrent(char);
    bool isWhitespace(char) const;
    bool isDigit(char) const;
    bool isLetter(char) const;
    bool isLowercaseLetter(char) const;
    bool isUppercaseLetter(char) const;
    std::string readWhitespace(void);
    std::string readInt(void);
    std::string readId(void);
    std::string input;
    int inputPtr;
    char currentChar;
    const char EOF_CHAR;
};

词法分析器.cpp

#include "Lexer.h"

Lexer::Lexer(std::string _input)
    : input(_input), EOF_CHAR(-1)
{

}

Lexer::~Lexer(void)
{
}

std::vector<Token> Lexer::lex(void)
{
    // Reset input pointer
    inputPtr = 0;
    updateCurrentChar();
    // Read tokens until EOF
    std::vector<Token> tokens;
    Token *token = nullptr;
    do
    {
        token = getNext();
        tokens.push_back(*token);
    } while(token->type != TokenType::_EOF);
    return tokens;
}

void Lexer::updateCurrentChar(void)
{
    currentChar = inputPtr < input.length()
        ? input[inputPtr]
        : EOF_CHAR;
}

void Lexer::increment(void)
{
    inputPtr++;
    updateCurrentChar();
}

bool Lexer::matchCurrent(char toMatch)
{
    if(toMatch == currentChar)
    {
        increment();
        return true;
    }
    return false;
}

Token* Lexer::getNext(void)
{
    Token token;
    if(isWhitespace(currentChar))
    {
        token.type = TokenType::WHITESPACE;
        token.detail = readWhitespace();
        return &token;
    }
    if(isDigit(currentChar))
    {
        token.type = TokenType::INT;
        token.detail = readInt();
        return &token;
    }
    if(isLetter(currentChar))
    {
        token.type = TokenType::ID;
        token.detail = readId();
        return &token;
    }
    if(currentChar == EOF_CHAR)
    {
        token.type = TokenType::_EOF;
        return &token;
    }
    switch(currentChar)
    {
    case ';':
        token.type = TokenType::SEMICOLON;
    case '=':
        token.type = TokenType::EQUALS;
    case '<':
        token.type = TokenType::LESS_THAN;
    case '>':
        token.type = TokenType::GREATER_THAN;
    case '+':
        token.type = TokenType::PLUS;
    default:
        token.type = TokenType::ERROR;
        token.detail = currentChar;
    }
    increment();
    return &token;
}

std::string Lexer::readWhitespace(void)
{
    std::string ws;
    while(isWhitespace(currentChar))
    {
        ws += currentChar;
        increment();
    }
    return ws;
}

std::string Lexer::readInt(void)
{
    std::string ws;
    while(isDigit(currentChar))
    {
        ws += currentChar;
        increment();
    }
    return ws;
}

std::string Lexer::readId(void)
{
    std::string ws;
    while(isWhitespace(currentChar))
    {
        ws += currentChar;
        increment();
    }
    return ws;
}

bool Lexer::isDigit(char c) const
{
    return c >= '0' && c <= '9';
}

bool Lexer::isLetter(char c) const
{
    return isLowercaseLetter(c)
        || isUppercaseLetter(c);
}

bool Lexer::isLowercaseLetter(char c) const
{
    return c >= 'a' && c <= 'z';
}

bool Lexer::isUppercaseLetter(char c) const
{
    return c >= 'A' && c <= 'Z';
}

bool Lexer::isWhitespace(char c) const
{
    switch(c)
    {
    case ' ':
    case '\n':
    case '\t':
    case '\r':
        return true;
    default:
        return false;
    }
}

最佳答案

问题是您在 getNext 中返回了一个指向局部变量的指针。请记住,当函数返回时,所有局部变量都被破坏,因此指针现在指向一个被破坏的对象。或者,由于局部变量在栈上,并且栈在函数调用之间重复使用,它现在可以指向完全不同的东西。然后取消引用这个现在无效的指针的结果会导致未定义的行为,并且未定义的行为导致崩溃很常见,但它也可能似乎有效,但数据是完全搞砸了。

显而易见的解决方案当然是返回对象的拷贝,即不要使用指针(这通常是一个很好的提示)。

关于c++ - std::vector.push_back() 抛出 badalloc 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18161787/

相关文章:

c++ - 如何使用二维阵列打印电路板?

c++ - 结构中引用的间接指针的意外地址,而不是使用普通变量的相同声明?

c++ - 错误C++: ‘const_iterator’没有命名类型;

c++ - vector 无法正常工作的功能

c++ - 使用 push_back 时,std::unique_ptr 是否移入了 std::vector?

c++ - glGetIntegerv 返回 36064

JAVA - 仅当我使用调试运行它时才会出现异常

exception - Haskell 中的安全应用

java - 在 Java 中实现启用/禁用方法的最佳方法是什么?

c++ - 使用迭代器对 vector 进行合并排序