代码之家  ›  专栏  ›  技术社区  ›  Jaldhar

如何在使用std::shared\u ptr的代码中防止内存泄漏

  •  -1
  • Jaldhar  · 技术社区  · 6 年前

    最近我一直在用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;
    }
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   Brian Bi    6 年前

    如何在使用std::shared\u ptr的代码中防止内存泄漏

    避免生吃 new delete . 始终使用 std::unique_ptr std::shared_ptr std::make_shared std::make_unique 创建智能指针所拥有的对象。不要打电话 .release() unique_ptr s。差不多了。