#include <iostream>
#include <vector>
#include <memory>
#define IS_DIGIT(x) x >= 48 && x <= 67
static unsigned int allocated = 0;
void* operator new(size_t size)
{
allocated += size;
void* mem = malloc(size);
//std::cout << "allocating: " << mem << " with size: " << size << std::endl;
return mem;
}
static unsigned int deleted = 0;
void operator delete(void* ptr, size_t size)
{
deleted += size;
//std::cout << "deleting: " << ptr << " with size: " << size << std::endl;
free(ptr);
}
enum class Type
{
None, Number, Operator
};
std::ostream& operator<<(std::ostream& os, Type& type)
{
switch (type)
{
case Type::None:
os << "None";
break;
case Type::Number:
os << "Number";
break;
case Type::Operator:
os << "Operator";
break;
default:
std::cout << "Unknown type for: " << &type << std::endl;
break;
}
return os;
}
class Token
{
public:
Type type = Type::None;
virtual void Fn() {};
};
class Number : public Token
{
public:
int value;
Number(int _value)
: value(_value) {
type = Type::Number;
}
};
class Operator : public Token
{
public:
Operator()
{
type = Type::Operator;
}
virtual Number Operate(const Number& num1, const Number& num2) = 0;
};
class Plus : public Operator
{
public:
Number Operate(const Number& num1, const Number& num2) override
{
return Number(num1.value + num2.value);
}
};
class Minus : public Operator
{
public:
Number Operate(const Number& num1, const Number& num2) override
{
return Number(num1.value - num2.value);
}
};
void Tokenize(const std::string& input, std::vector<std::unique_ptr<Token>>& vec)
{
std::string number;
for (auto& c : input)
{
if (c == '\n' || c == ' ' || !c) continue;
std::cout << "char: " << c << std::endl;
if (IS_DIGIT(c)) number.push_back(c);
else
{
vec.push_back(std::move(std::make_unique<Number>(std::stoi(number.c_str()))));
number.clear();
switch (c)
{
case '+':
vec.push_back(std::move(std::make_unique<Plus>()));
break;
case '-':
vec.push_back(std::move(std::make_unique<Minus>()));
break;
default:
std::cout << "Unknown operator: " << c << std::endl;
break;
}
}
}
// for last digit
if (!number.empty())
vec.push_back(std::move(std::make_unique<Number>(std::stoi(number.c_str()))));
}
int main()
{
// main scope
{
std::vector<std::unique_ptr<Token>> tokens;
Tokenize(" 78 + 1 *5-3", tokens);
for (auto& i : tokens)
{
std::cout << "type: " << i.get()->type;
Number* op = dynamic_cast<Number*>(i.get());
if (op)
std::cout << " num: " << op->value;
std::cout << std::endl;
}
}
std::cout << "total allocated: " << allocated << std::endl;
std::cout << "total deleted: " << allocated << std::endl;
return 0;
}能不能有人聪明,请检查我的代码无效率和更好的优化?而且,我甚至不确定我是否做得对。提前感谢
发布于 2023-03-16 14:35:06
小心宏。如果IS_DIGIT()在算术运算符旁边展开,您将得到令人惊讶的结果,因为它不像函数调用。
#define IS_DIGIT(x) ((x) >= 48 && (x) <= 67)它仍然不是一个很好的宏,因为它不止一次地扩展x,这会导致它的副作用重复发生。让它成为一个函数--或者只使用std::isdigit(),它无缝地适应执行字符集,而不是假设输入总是ASCII。
我们不应该声明我们自己的new和delete。如果我们发现有必要,我们应该正确地实现new:
if (!mem) throw std::bad_alloc();我们需要包括<cstdlib>来声明std::malloc()和std::free()。
错误消息应该转到错误流,而不是输出流:
default:
std::cerr << "Unknown type for: " << &type << '\n';Token是一个基类,应该有一个虚拟析构函数。
声明Token::Fn() = 0 (有或没有身体)使其成为纯粹的抽象可能是个好主意。或者只是移除它,因为它似乎从未被使用过。
Number构造函数应该是explicit。
在适当的情况下很好地使用override。
缺少的包括<string>。
这看起来像日志记录:
std::cout << "char: " << c << std::endl;
因此,它应该转到std::clog。
当应用于rvalue时,std::move()是没有操作的,所以在Tokenise()中调用它的地方并不有用。我们错过了它的包含(<utility>)。
如果我们不打算修改值,请使用const:
for (auto const& i : tokens)考虑使用std::shared_ptr,这样我们就可以使用dynamic_pointer_cast()而不是dynamic_cast(get())。
https://codereview.stackexchange.com/questions/283993
复制相似问题