I have read that one must not store std::auto_ptr in std::vector and that boost::ptr_vector could be used instead. I have been able to do so, I don't know however how to use ptr_vector, when I don't want to store pointers, but a struct, which has a pointer member.
In this example, I want to open some files and store the associated ofstream object with some additional data, for later use. I would like to replace the file field of struct data with a smart pointer. Since the vector<data> v should be the owner, I think that a shared_ptr would work, but wouldn't be appropriate.
What should I replace the naked pointer file with?
#include <iostream>
#include <fstream>
#include <vector>
struct data {
std::string filename;
std::ofstream* file;
data(const std::string filename, std::ofstream* file)
: filename(filename), file(file)
{
}
};
std::vector<data> open_files()
{
std::vector<data> v;
v.push_back(data("foo", new std::ofstream("foo")));
return v;
}
int main()
{
std::vector<data> v = open_files();
/* use the files */
*(v[0].file) << "foo";
delete v[0].file; // either rely on dtor to close(), or call it manually
}
Update:
I feel I have done a sub optimal job in describing my problem, let me try with another example. Also I am looking for a C++03 solution:
#include <memory>
#include <vector>
#include <boost/ptr_container/ptr_vector.hpp>
struct T {
std::auto_ptr<int> a;
};
int main()
{
// instead of
// std::vector<std::auto_ptr<int> > v;
// use
boost::ptr_vector<int> v;
// what to use instead of
// std::vector<T> w;
}
Concerning your data class, I would suggest using an std::unique_ptr<std::ofstream>. This is not to save you from an accidental memory leak, since you are deleting the pointer in the constructor, but rather to make the ownership explicit. A user of your code would have to know what data is doing with the pointer it takes in the constructor:
std::ofstream ofs;
{
data d1("crash", &ofs);
} // error! d1 will attempt to delete stack allocated object
std::ofstream* pOfs = new std::ofstream(....);
data d2("crash again", pOfs);
delete pOFs; // user thinks data makes a deep copy
However, with unique_ptr the intend is clear, hence it is harder to make mistakes:
data d3("OK", std::unique_ptr<std::ofstream>(new std::ofstream(....)));
std::unique_ptr<std::ofstream> pOfs2(new std::ofstream(....));
data d4("OK", pOfs2); // safe, pOfs's contents have been safely moved
// we can check pOfs2 after the move
if (pOfs2) { /* */ }
You can delete pointer in destructor:
struct data
{
std::string filename;
std::ofstream* file;
data(const std::string filename, std::ofstream* file)
: filename(filename), file(file)
{
}
~data()
{
delete file;
}
};
Or use std::unique_ptr to wrap that pointer but its unnecessary in your case.
You don't need to have an ofstream* as a member.
#include <iostream>
#include <fstream>
#include <vector>
struct data {
std::string filename;
data(const std::string filename) : filename(filename)
{}
};
std::vector<data> open_files()
{
std::vector<data> v;
v.push_back(data("foo"));
return v;
}
If you want to append to the file, specify the app file mode.
void print_files(const std::vector<data>& v)
{
for(std::vector<data>::const_iterator it = v.begin(); it != v.end(); ++it)
{
std::ofstream os(it->filename, std::ostream::app);
os << "bar";
}
}
int main()
{
std::vector<data> v = open_files();
print_files(v);
}
Related
I want to take input from an istream from either a std::ifstream or std::cin depending on some condition.
As far as I can get it working, I had to use a raw std::istream* pointer:
int main(int argc, char const* argv[]) {
std::istream *in_stream;
std::ifstream file;
if (argc > 1) {
std::string filename = argv[1];
file.open(filename);
if (not file.is_open()) {
return -1;
}
in_stream = &file;
} else {
in_stream = &std::cin;
}
// do stuff with the input, regardless of the source...
}
Is there a way to rewrite the above using smart pointers?
This may be a question about ownership: How does one wrap and pass around two different std::istream instances, one of which is owned and needs disposal (which calls close() upon destruction) and ownership transfers, whereas the other one is not owned by user code (e.g. std::cin) and cannot be deleted. The solution is polymorphism: Create an interface like
struct StreamWrapper {
virtual std::istream &stream() = 0;
virtual ~StreamWrapper() = default;
};
and two implementations, e.g. OwnedStreamWrapper and UnownedStreamWrapper. The former can contain a std::istream directly (which is moveable, but not copyable) and the latter can contain (e.g.) a std::istream&, i.e. have no ownership over the referenced stream instance.
struct OwnedStreamWrapper : public StreamWrapper {
template <typename... A>
OwnedStreamWrapper(A &&...a) : stream_{std::forward<A>(a)...} {}
std::istream &stream() override { return stream_; }
private:
std::ifstream stream_;
};
struct UnownedStreamWrapper : public StreamWrapper {
UnownedStreamWrapper(std::istream &stream) : stream_{stream} {}
std::istream &stream() override { return stream_; }
private:
std::istream &stream_;
};
Apart from the stream ownership, wrapper ownership matters as well and can be used either to handle the wrappers’ (and streams’) lifespan automatically on the stack, or to allow a wrapper’s lifespan to exceed that of the current stack frame. In the example below, the first ReadWrapper() takes ownership of the wrapper and deletes it automatically whereas the second ReadWrapper() does not take ownership. In both cases polymorphism (i.e. the implementation of StreamWrapper) determines how the underlying stream is handled, i.e. whether it outlives its wrapper (like std::cin should) or dies together with it (like a manually instantiated stream should).
void ReadWrite(std::istream &in, std::ostream &out) {
std::array<char, 1024> buffer;
while (in) {
in.read(buffer.data(), buffer.size());
out.write(buffer.data(), in.gcount());
}
}
void ReadWrapper(std::unique_ptr<StreamWrapper> stream) {
ReadWrite(stream->stream(), std::cout);
}
void ReadWrapper(StreamWrapper &stream) {
ReadWrite(stream.stream(), std::cout);
}
Below are all four combinations of { owned | unowned } { streams | stream wrappers } in a runnable example:
#include <array>
#include <fstream>
#include <iostream>
#include <memory>
#include <utility>
namespace {
/********** The three snippets above go here! **********/
} // namespace
int main() {
OwnedStreamWrapper stream1{"/proc/cpuinfo"};
std::unique_ptr<StreamWrapper> stream2{
std::make_unique<OwnedStreamWrapper>("/proc/cpuinfo")};
std::ifstream stream3_file{"/proc/cpuinfo"}; // Let’s pretend it is unowned.
UnownedStreamWrapper stream3{stream3_file};
std::ifstream stream4_file{"/proc/cpuinfo"}; // Let’s pretend it is unowned.
std::unique_ptr<StreamWrapper> stream4{
std::make_unique<UnownedStreamWrapper>(stream4_file)};
ReadWrapper(stream1); // owned stream, wrapper kept
ReadWrapper(std::move(stream2)); // owned stream, wrapper transferred
ReadWrapper(stream3); // unowned stream, wrapper kept
ReadWrapper(std::move(stream4)); // unowned stream, wrapper transferred
}
A smart pointer is kind of an awkward fit for this situation, because it requires a dynamic allocation (which is probably not necessary in this case)
1. Do your processing in another function
As #BoP pointed out in the comments a nice way to handle this could be to use another function that gets passed the appropriate input stream:
godbolt
int do_thing(std::istream& in_stream) {
// do stuff with the input, regardless of the source...
int foobar;
in_stream >> foobar;
return 0;
}
int main(int argc, char const* argv[]) {
std::ofstream{"/tmp/foobar"} << 1234;
if(argc > 1) {
std::ifstream file{argv[1]};
if(!file) return -1;
return do_thing(file);
} else {
return do_thing(std::cin);
}
}
2. Switch the stream buffer
If you won't be using std::cin at all if a filename is passed you could change the streambuffer of std::cin to the one of the file with rdbuf() - that way you can use std::cin in both cases.
godbolt
std::ifstream file;
std::streambuf* oldbuf = std::cin.rdbuf();
if (argc > 1) {
file.open(argv[1]);
if (!file) return -1;
// switch buffer of std::cin
std::cin.rdbuf(file.rdbuf());
}
// do stuff with the input, regardless of the source...
int foobar;
std::cin >> foobar; // this will reader either from std::cin or the file, depending on the current streambuffer assigned to std::cin
// restore old stream buffer
std::cin.rdbuf(oldbuf);
3. Using std::unique_ptr / std::shared_ptr with a custom deleter
The easiest solution if you still want to use smart pointers would be to use std::unique_ptr / std::shared_ptr with a custom deleter that handles the std::cin case:
godbolt
// deletes the stream only if it is not std::cin
struct istream_ptr_deleter {
void operator()(std::istream* stream) {
if(&std::cin == stream) return;
delete stream;
}
};
using istream_ptr = std::unique_ptr<std::istream, istream_ptr_deleter>;
// Example Usage:
istream_ptr in_stream;
if (argc > 1) {
in_stream.reset(new std::ifstream(argv[1]));
if (!*in_stream) return -1;
} else {
in_stream.reset(&std::cin);
}
int foobar;
*in_stream >> foobar;
Why this can't work. Is there any way to do this?
I don't want to create a separate function for pointers
#include <iostream>
using namespace std;
template<class T>
class temp
{
public:
T val;
temp(T value) : val(value) {}
~temp()
{
if(is_pointer<T>::value)
{
delete val;
}
}
};
int main()
{
string * n = new string("cat");
temp<string*>object(n);//ok
temp<string>object2("dog"); //compliation error: type 'class std::cxx11::basic_string' argument given to 'delete', expected pointer. --- (but there is if statement!!!!)
//i dont want delete in main
return 0;
}
To compile i use g++ 6.3.0
Could someone help? Maybe, I need to separate declaration from definition?
The issue that you have is that the branch of an if must always be syntactically valid, even if it is never taken.
You could do it with if constexpr, which is a "compile time if"
~temp()
{
if constexpr(is_pointer<T>::value)
{
delete val;
}
}
However this isn't safe.
How do you know that the pointer passed to temp<T*> was created by new and not new[], malloc, or by taking the address of an object that wasn't dynamically allocated?
Rather than assume that pointers should be deleted, you should avoid having to know which pointers to delete
#include <string>
#include <memory>
template<class T>
class temp
{
public:
T val;
temp(T value) : val(value) {}
// n.b. no need to define destructor
};
int main()
{
std::string str("cat");
temp<std::string*> object(&str);//ok
temp<std::string> object2("dog"); // also ok
std::unique_ptr<std::string> str2 = std::make_unique<std::string>("mouse");
temp<std::string *> object3(str2.get()); // ok so long as str2 outlives object3
std::shared_ptr<std::string> str3 = std::make_shared<std::string>("rabbit");
temp<std::shared_ptr<std::string>> object4(str3); // also ok
return 0;
}
There are situations in which I need to pass a char* buffer back and forth. My idea is to create an object which can hold the object that owns the data, but also expose the data as char* for someone to read. Since this object holds the owner, there are no memory leaks because the owner is destructed with the object when it's no longer necessary.
I came with the implementation below, in which we have a segfault that I explain why it happens. In fact it's something that I know how to fix but it's something that my class kinda lured me into doing. So I consider what I've done to be not good and maybe there's a better way of doing this in C++ that is safer.
Please take a look at my class that holds the buffer owner and also holds the raw pointer to that buffer. I used GenericObjectHolder to be something that holds the owner for me, without my Buffer class being parametrized by this owner.
#include <iostream>
#include <string>
#include <memory>
#include <queue>
//The library:
class GenericObjectHolder
{
public:
GenericObjectHolder()
{
}
virtual ~GenericObjectHolder() {
};
};
template <class T, class Holder = GenericObjectHolder>
class Buffer final
{
public:
//Ownership WILL be passed to this object
static Buffer fromOwned(T rawBuffer, size_t size)
{
return Buffer(std::make_unique<T>(rawBuffer), size);
}
//Creates a buffer from an object that holds the buffer
//ownership and saves the object too so it's only destructed
//when this buffer itself is destructed
static Buffer fromObject(T rawBuffer, size_t size, Holder *holder)
{
return Buffer(rawBuffer, std::make_unique<T>(rawBuffer), size, holder);
}
//Allocates a new buffer with a size
static Buffer allocate(size_t size)
{
return Buffer(std::make_unique<T>(new T[size]), size);
}
~Buffer()
{
if (_holder)
delete _holder;
}
virtual T data()
{
return _rawBuffer;
}
virtual size_t size() const
{
return _size;
}
Buffer(T rawBuffer, std::unique_ptr<T> buffer, size_t size)
{
_rawBuffer = rawBuffer;
_buffer = std::move(buffer);
_size = size;
}
Buffer(T rawBuffer, std::unique_ptr<T> buffer, size_t size, Holder *holder)
{
_rawBuffer = rawBuffer;
_buffer = std::move(buffer);
_size = size;
_holder = holder;
}
Buffer(const Buffer &other)
: _size(other._size),
_holder(other._holder),
_buffer(std::make_unique<T>(*other._buffer))
{
}
private:
Holder *_holder;
T _rawBuffer;
std::unique_ptr<T> _buffer;
size_t _size = 0;
};
//Usage:
template <class T>
class MyHolder : public GenericObjectHolder
{
public:
MyHolder(T t) : t(t)
{
}
~MyHolder()
{
}
private:
T t;
};
int main()
{
std::queue<Buffer<const char*, MyHolder<std::string>>> queue;
std::cout << "begin" << std::endl;
{
//This string is going to be deleted, but `MyHolder` will still hold
//its buffer
std::string s("hello");
auto h = new MyHolder<std::string>(s);
auto b = Buffer<const char*, MyHolder<std::string>>::fromObject(s.c_str(),s.size(), h);
queue.emplace(b);
}
{
auto b = queue.front();
//We try to print the buffer from a deleted string, segfault
printf(b.data());
printf("\n");
}
std::cout << "end" << std::endl;
}
As you see, the s string is copied inside the object holder but gets destructed right after it. So when I try to access the raw buffer that buffer owns I get a segfault.
Of course I could simply copy the buffer from the s string into a new buffer inside my object, but It'd be inefficient.
Maybe there's a better way of doing such thing or maybe there's even something ready in C++ that does what I need.
PS: string is just an example. In pratice I could be dealing with any type of object that owns a char* buffer.
Live example: https://repl.it/repls/IncredibleHomelySdk
Your core problem is that you want your Holder to be moveable. But when the Owner object moves, the buffer object might also move. That will invalidate your pointer. You can avoid that by putting the owner in a fixed heap location via unique_ptr:
#include <string>
#include <memory>
#include <queue>
#include <functional>
template <class B, class Owner>
class Buffer
{
public:
Buffer(std::unique_ptr<Owner>&& owner, B buf, size_t size) :
_owner(std::move(owner)), _buf(std::move(buf)), _size(size)
{}
B data() { return _buf; }
size_t size() { return _size; }
private:
std::unique_ptr<Owner> _owner;
B _buf;
size_t _size;
};
//Allocates a new buffer with a size
template<typename T>
Buffer<T*, T[]> alloc_buffer(size_t size) {
auto buf = std::make_unique<T[]>(size);
return {std::move(buf), buf.get(), size};
}
Here's a repl link: https://repl.it/repls/TemporalFreshApi
If you want to have a type-erased Buffer, you can do that like this:
template <class B>
class Buffer
{
public:
virtual ~Buffer() = default;
B* data() { return _buf; }
size_t size() { return _size; }
protected:
Buffer(B* buf, size_t size) :
_buf(buf), _size(size) {};
B* _buf;
size_t _size;
};
template <class B, class Owner>
class BufferImpl : public Buffer<B>
{
public:
BufferImpl(std::unique_ptr<Owner>&& owner, B* buf, size_t size) :
Buffer<B>(buf, size), _owner(std::move(owner))
{}
private:
std::unique_ptr<Owner> _owner;
};
//Allocates a new buffer with a size
template<typename T>
std::unique_ptr<Buffer<T>> alloc_buffer(size_t size) {
auto buf = std::make_unique<T[]>(size);
return std::make_unique<BufferImpl<T, T[]>>(std::move(buf), buf.get(), size);
}
Again, repl link: https://repl.it/repls/YouthfulBoringSoftware#main.cpp
You wrote:
There are situations in which I need to pass a char* buffer back and
forth.
and
So I consider what I've done to be not good and maybe there's a better
way of doing this in C++ that is safer.
It's not exactly clear what you are aiming at, but when I have this need i will sometimes use std::vector<char> - a std::vector (and std::string) is a just that: a managed buffer. Calling data() on vector will give you a raw pointer to the buffer to pass on to legacy interfaces etc. or for whatever reason you just need a buffer that you manage yourself. Hint: use resize() or constructor to allocate the buffer.
So you see, there's no need to store the internal pointer of std::string in your example. Instead just call data() on a need basis.
It seems like you are concerned about copies and efficiency. If you use objects that support move semantics and you use the emplace family of functions there shouldn't be any copy-ing going on at least in c++17. All/most containers supports moving as well.
The class std::unique_ptr is already a "buffer holder" that "guarantee delete", no string copies, no dangling references and no seg faults:
#include <iostream>
#include <queue>
#include <memory>
int main()
{
std::queue<std::unique_ptr<std::string>> queue;
std::cout << "begin" << std::endl;
{
auto h = std::make_unique<std::string>("Hello");
queue.emplace( std::move(h) ); // move into the queue without copy
}
{
auto b = std::move(queue.front()); // move out from queue without copy
std::cout << *b << std::endl;
} // when b goes out of scope it delete the string
std::cout << "end" << std::endl;
}
https://godbolt.org/z/neP838
I would like to copy the address of an object to a buffer and typecast it back at some other point. I am unable to do it. A sample code is given below.
#include <iostream>
#include <cstring>
class MyClass
{
public:
MyClass(const int & i)
{
id = i;
}
~MyClass()
{
}
void print() const
{
std::cout<<" My id: "<<id<<std::endl;
}
private:
int id;
};
int main()
{
MyClass *myClass = new MyClass(10);
std::cout<<"myClass: "<<myClass<<std::endl;
myClass->print();
// Need to copy the address to a buffer and retrieve it later
char tmp[128];
// std::vector tmp(sizeof(myClass); // preferably, we may use this instead of the previous line, and use std::copy instead of memcpy
memcpy(tmp, myClass, sizeof(myClass));
// retreiving the pointer
MyClass* myClassPtr = (MyClass*) tmp;
std::cout<<"myClassPtr: "<<myClassPtr<<std::endl;
myClassPtr->print();
return 0;
}
In fact, the pointers gives different values, which is the source of the problem. What am I doing wrong here?
You are copying (a pointer-sized part of) the object itself, not the pointer. You should do:
memcpy(tmp, &myClass, sizeof(myClass));
and then back:
MyClass *ptr;
memcpy(&ptr, tmp, sizeof(ptr));
When writing a custom serializer for msgpack_c one also needs to implement object_with_zone.
The documentation how to implement this is very sparse ( https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_adaptor ).
In what circumstances is this method called?
You can create a msgpack::object from C++ types.
See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_object#conversion
When you call msgpack::object constructor with zone like msgpack::object(mc, z);, object_with_zone<T>::operator() is called internally.
If you don't want to create msgpack::object from C++ types, you don't need to define object_with_zone specialization. Packing, unpacking, and converting to C++ types from msgpack::object don't require it.
Here is an example:
#include <iostream>
#include <msgpack.hpp>
class my_class {
public:
my_class(std::string const& name, int age):name_(name), age_(age) {}
std::string const& get_name() const { return name_; }
int get_age() const { return age_; }
private:
std::string name_;
int age_;
};
// User defined class template specialization
namespace msgpack {
MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) {
namespace adaptor {
template <>
struct object_with_zone<my_class> {
void operator()(msgpack::object::with_zone& o, my_class const& v) const {
std::cout << "object_with_zone<my_class> is called" << std::endl;
o.type = type::ARRAY;
o.via.array.size = 2;
o.via.array.ptr = static_cast<msgpack::object*>(
o.zone.allocate_align(sizeof(msgpack::object) * o.via.array.size, MSGPACK_ZONE_ALIGNOF(msgpack::object)));
o.via.array.ptr[0] = msgpack::object(v.get_name(), o.zone);
o.via.array.ptr[1] = msgpack::object(v.get_age(), o.zone);
}
};
} // namespace adaptor
} // MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS)
} // namespace msgpack
int main() {
my_class mc("John", 42);
msgpack::zone z;
auto obj = msgpack::object(mc, z);
std::cout << obj << std::endl;
}
Output:
object_with_zone<my_class> is called
["John", 42]
Running demo: https://wandbox.org/permlink/dNmZX1FpUL3w8D5m
updated
Additional question. Why would i want to use the zone ?
Answer:
A zone is used internally when you unpack MessagePack formatted byte stream. You get msgpack::object_handle. msgpack::object_handle has a zone and a msgpack::object. See https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_object#what-is-msgpackobject.
The reason of using msgpack::zone is for performance. If msgpack::object is STR, BIN, or EXT, the msgpack::object need to allocate a memory dynamically. The msgpack::object can have a handle of the memory by itself but it is inefficient. The destructor of msgpack::object need to deallocate memory, if the msgpack::object allocate memory. msgpack::object is a composite data structure. That means the destructor cannot be inlined.
One of the goal of msgpack-c is efficient unpacking. So msgpack-c uses msgpack::zone.
It is unpacking story. msgpack::zone is also used when msgpack::object is created from C++ types. I'm not sure when users want to do, is is up to users.