如何使用智能指针进行自动清理?
How to use smart pointer for auto clean-up?
我正在使用指向 std::ofstream
或 std::cerr
的指针进行简单的日志记录 class。
有没有任何简单的方法可以使用智能指针进行自动清理,而不管使用哪个流?
代码必须在 clang++、g++ 和 VS2013 上编译。
代码
#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;
它给了我同样的 deleted constructor 错误。 p = &std::cout
抱怨类型不匹配,所以它也不起作用。
我倾向于尽量避免我想要一个对象 "own" 这样的事情。在我没有太多选择的时候,我最终选择了 "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
在不应删除智能指针的情况下,您可以通过在析构函数(和其他地方)中释放智能指针来做到这一点,但在我看来这不值得麻烦。
相反,我建议只使用两个指针:一个用于需要管理的流,一个用于不需要管理的流:
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;
}
};
如果保存 space 是优先事项,您可以将它们放在一个联合中,但是您必须显式调用析构函数和 placement new 来定义活动成员,这又更麻烦而且可能不值得。
您可以将 shared_ptr
与删除器一起使用,在 cerr
的情况下不删除任何内容,在 ofstream
的情况下只删除正常构造的 shared_ptr
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;
}
};
我只有两个指针,一个是智能的,一个是原始的。
原始指针始终用于引用流。智能指针仅在需要时用于清理。
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;
}
};
我正在使用指向 std::ofstream
或 std::cerr
的指针进行简单的日志记录 class。
有没有任何简单的方法可以使用智能指针进行自动清理,而不管使用哪个流?
代码必须在 clang++、g++ 和 VS2013 上编译。
代码
#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;
它给了我同样的 deleted constructor 错误。 p = &std::cout
抱怨类型不匹配,所以它也不起作用。
我倾向于尽量避免我想要一个对象 "own" 这样的事情。在我没有太多选择的时候,我最终选择了 "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
在不应删除智能指针的情况下,您可以通过在析构函数(和其他地方)中释放智能指针来做到这一点,但在我看来这不值得麻烦。
相反,我建议只使用两个指针:一个用于需要管理的流,一个用于不需要管理的流:
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;
}
};
如果保存 space 是优先事项,您可以将它们放在一个联合中,但是您必须显式调用析构函数和 placement new 来定义活动成员,这又更麻烦而且可能不值得。
您可以将 shared_ptr
与删除器一起使用,在 cerr
的情况下不删除任何内容,在 ofstream
的情况下只删除正常构造的 shared_ptr
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;
}
};
我只有两个指针,一个是智能的,一个是原始的。
原始指针始终用于引用流。智能指针仅在需要时用于清理。
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;
}
};