最近我一直在用c++开发一个scheme解释器。对于版本2,我重写了它,以便它在内部使用cons单元格的链接列表。到现在为止,一直都还不错。现在我正在实现append,它应该获取两个列表并将它们连接到两个一个列表中。下面显示的代码起作用。它输出:
(1,2)
(3,4)
(1,2,3,4)
所以我应该通过引用传递它们,或者以某种方式移动它们,对吗?不幸的是,我这样做的尝试导致了更多的错误。有人能告诉我如何使这个代码不泄漏吗?
typedef enum { CONS = 0, ATOM = 1, FUNCTION = 2, LAMBDA = 3 } Type;
class Expression {
public:
explicit Expression(Type type) : type_{type} {
}
virtual ~Expression() {}
Type type_;
};
class Cons : public Expression {
public:
Cons(Expression* car = nullptr, Expression* cdr = nullptr) :
Expression(Type::CONS), car_{car}, cdr_{cdr} {
}
~Cons() {
if (car_) {
delete car_;
}
}
Expression* car_;
std::shared_ptr<Expression> cdr_;
};
class Atom : public Expression {
public:
Atom(const char* value) : Expression(Type::ATOM), value_{value} {
}
Atom(std::string value) : Atom(value.c_str()) {
}
std::string value_;
};
std::ostream& operator<<(std::ostream& out, Expression* exp) {
switch(exp->type_) {
case Type::ATOM:
out << dynamic_cast<Atom*>(exp)->value_;
break;
case Type::CONS: {
out << "(";
auto current = dynamic_cast<Cons*>(exp);
while (current) {
out << current->car_;
if (current->cdr_) {
out << ' ';
}
current = dynamic_cast<Cons*>(current->cdr_.get());
}
out << ")";
break;
}
case Type::FUNCTION:
case Type::LAMBDA:
break;
}
return out;
}
void traverse(Expression* exp, std::function<void(Expression*)> process) {
if (exp) {
if (exp->type_ == Type::CONS) {
auto cell = dynamic_cast<Cons*>(exp);
traverse(cell->car_, process);
traverse(cell->cdr_.get(), process);
} else {
process(exp);
}
}
}
Expression* append(Expression* first, Expression* second) {
Cons* ret = nullptr;
auto add_to_ret = [&ret](Expression* cell) -> void {
if (ret == nullptr) {
ret = dynamic_cast<Cons*>(new Cons(cell));
} else {
auto temp = ret;
while(temp->cdr_) {
temp = dynamic_cast<Cons*>(temp->cdr_.get());
}
temp->cdr_.reset(new Cons(cell));
}
};
traverse(first, add_to_ret);
traverse(second, add_to_ret);
return ret;
}
int main() {
Expression* list1 = new Cons(
new Atom("1"),
new Cons(
new Atom("2"),
nullptr
)
);
std::cerr << list1 << '\n';
Expression* list2 = new Cons(
new Atom("3"),
new Cons(
new Atom("4"),
nullptr
)
);
std::cerr << list2 << '\n';
Expression* joined = new Cons(
list1,
nullptr
);
joined = append(joined, list2);
std::cout << joined << '\n';
if (joined) {
delete joined;
}
return EXIT_SUCCESS;
}