最近,我一直在使用c ++进行方案解释器。对于版本2,我已对其进行了重写,因此它在内部使用了con单元格的链接列表。到目前为止,一切都很好。现在,我正在实现append,它应该包含两个列表并将它们连接成两个一个列表。下面显示的代码有效。它输出:
(1,2)
(3,4)
(1,2,3,4)
应当如此。但是valgrind揭示它正在泄漏内存。 (绝对丢失:2个字节中的80个字节,间接丢失:8个块中的240个字节)我认为这是因为我在main()中创建的所有对象的指针都被复制到Cons的构造函数中,并且该副本永远不会被删除。这是正确的吗?
所以我应该以引用的方式传递它们,或者以某种方式正确移动它们?不幸的是,我这样做的尝试导致了更多错误。谁能告诉我如何使此代码无泄漏?
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;
}
答案 0 :(得分:2)
如何防止使用std :: shared_ptr的代码中的内存泄漏
避免使用原始new
和delete
。需要拥有指针时,请始终使用std::unique_ptr
或std::shared_ptr
。仅将原始指针用作非所有权句柄。使用std::make_shared
和std::make_unique
创建智能指针拥有的对象。不要在.release()
上致电unique_ptr
。就是这样。