如何使用智能指针进行自动清理?

时间:2015-07-31 16:15:00

标签: c++ pointers c++11 stream smart-pointers

我正在创建一个简单的日志记录类,其中包含指向text-indent: -9999px;std::ofstream的指针。

有没有使用智能指针进行自动清理的简单方法,无论使用哪种流?

代码必须在clang ++,g ++和VS2013上编译。

代码

std::cerr

尝试

#include <iostream> #include <fstream> #include <string> class Logger { private: std::ostream * output_stream{ nullptr }; bool using_file{ false }; public: Logger() { output_stream = &std::cerr; using_file = false; } Logger(std::string file) { output_stream = new std::ofstream(file); using_file = true; } ~Logger() { if (using_file) { delete output_stream; } } template<typename T> void log(T info) { *output_stream << info << std::endl; } }; class tmp { int i{ 4 }; friend std::ostream & operator<<(std::ostream &os, const tmp& p); }; std::ostream &operator<<(std::ostream &os, const tmp& p) { return os << p.i; } int main() { tmp t; Logger logger; logger.log(t); system("pause"); return 0; }

我可以使用std::unique_ptr这样的文件:

std::unique_ptr

尝试使用std::unique_ptr<std::ostream> p; p = std::make_unique<std::ofstream>("file.txt"); *p << "hi there" << std::endl; 警告我有关已删除的函数(假设它是构造函数。

std::cout

std::unique_ptr<std::ostream> p2; p2 = std::make_unique<std::ostream>(std::cout); *p2 << "hey" << std::endl;

由于std::shared_ptr仅用于拥有内容,并且std::unique_ptr不应归属,我认为我会尝试std::cout

std::shared_ptr

它给了我相同的删除构造函数错误。 std::shared_ptr<std::ostream> p; p = std::make_shared<std::ostream>(std::cout); *p << "hola" << std::endl; 抱怨类型不匹配,因此它也无效。

4 个答案:

答案 0 :(得分:4)

shared_ptr的情况下,您可以将cerr与不删除任何内容的删除者一起使用,shared_ptr ofstream p>

class Logger {
private:
    std::shared_ptr<std::ostream> output_stream{ nullptr };

public:
    Logger() :
        output_stream(&std::cerr, [](std::ostream*){})
    { }

    Logger(std::string file) :
        output_stream(std::make_shared<std::ofstream>(file))
    { }

    // default destructor is OK

    template<typename T>
    void log(T info)
    {
        *output_stream << info << std::endl;
    }
};

答案 1 :(得分:4)

我只有两个指针,一个聪明,一个原始。

原始指针始终用于引用流。如果需要,智能指针仅用于清理。

class Logger {
private:
    std::unique_ptr<std::ofstream> file_stream;
    std:ostream *stream;
public:
    Logger() : stream(&std::cerr) {}
    Logger(const std::string& file)
    : file_stream(std::make_unique<std::ofstream>(file)), stream(file_stream.get()){}

    template<typename T>
    void log(T info) {
        *stream << info << std::endl;
    }
};

答案 2 :(得分:1)

我倾向于尝试避免我希望对象“拥有”这类事物的情况。在我没有太多选择的时候,我最终选择了“shouldDelete”旗帜或回调。

class Logger {
public:
    Logger(std::ofstream *outputStream, bool deleteOutputStream)
        : outputStream(outputStream), deleteOutputStream(deleteOutputStream)
    {  }
    ~Logger()
    {
        if (deleteOutputStream) delete outputStream;
    }
};
Logger logger(&std::cout, false);

class Logger {
public:
    typedef std::function<void(std::ostream*)> Deleter;
    typedef std::unique_ptr<std::ostream, Deleter> OStreamPointer;
    Logger(OStreamPointer &&outputStream)
        : outputStream(std::move(outputStream))
    {  }
    ~Logger() { }
private:
    OStreamPointer outputStream;
};

Logger logger(Logger::OStreamPointer(
    &std::cout,
    [](std::ostream*) {})); //no-op callback

答案 3 :(得分:1)

你可以通过在不应该删除它的情况下释放析构函数(以及其他地方)中的智能指针来做到这一点,但这不值得麻烦的IMO。

相反,我建议只使用两个指针:一个用于需要管理的流,一个用于那些不需要管理的流:

class Logger {
private:
    std::ostream * unmanaged_stream{ nullptr };
    std::unique_ptr<std::ostream> managed_stream{ nullptr };
    bool using_file{ false };
    std::ostream& output_stream()
    {
        return using_file ? *managed_stream : *unmanaged_stream;
    }
public:
    Logger()
    : unmanaged_stream{&std::cerr},
      using_file{false}
    {
    }
    Logger(const std::string& file)
    : managed_stream{std::make_unique<std::ofstream>(file)},
      using_file{true}
    {
    }
    template<typename T>
    void log(T info)
    {
        output_stream() << info << std::endl;
    }
};

如果保存空间是一个优先级你可以把它们放在一个联合中,但是你必须明确地调用析构函数和placement new来定义活动成员,这又更麻烦,可能不值得。