Skip to main content
Tweeted twitter.com/#!/StackProgrammer/status/631760524917739521
edited title
Link
Robert Harvey
  • 200.7k
  • 55
  • 470
  • 683

RAII and libraries Possible alternatives to copy constructors

Noting that the wrapper contains special functions for working with the wrapped object
Source Link

In my C++ project I am relying on some libraries that do memory management for me. I make wrapper classes, for ease of use and memory safety, for example the class below. Note that this is a much simplified example, to demonstrate my problem.

#include <library> class Wrapper { private: lib_type* data; public: Wrapper() : data(library_new()) { } Wrapper(const Wrapper& orig) = delete; ~Wrapper() { library_free(data); } const lib_type* getData() const { return data; }  /* ... */ /* Lots of functions for using the wrapped object */ }; 

I needed to delete the copy constructor, because otherwise a copy going out of scope would invalidate the original object. Not being allowed to have copies makes the object very impractical to use - everywhere it is used I now need to hold a reference, and I need to manage the object centrally, which partially defeats the purpose of the wrapper class.

Possible solutions I have tried/thought of:

  • Copying the data. This is normally not an option though, because it is either not allowed by the library or the data is huge.
  • Move constructors. I tried solving the lack of a copy constructor by using a move constructor, but depending on the implementation, either this did not solve the problem or it became effectively a copy constructor, reintroducing the related problems.
  • Smart pointers. Then I realized it might be solved by using smart pointers to the wrapper instead of references, as this removes the need to maintain a central copy.
  • Wrapping a smart pointer. Or I could wrap a smart pointer to the data instead of a raw pointer. This makes the implementation of the wrapper a little bit more complicated, but also makes it easier to use, giving the classes using it a cleaner interface.

My attempt at the second smart pointer solution applied to the example above:

#include <library> class Deleter { public: void operator()(lib_type* p) const { library_free(p); } }; class Wrapper { private: shared_ptr<lib_type> data; public: Wrapper() : data(library_new(), Deleter()) { } Wrapper(const Wrapper& orig) : data(orig.data) { } ~Wrapper() { } const lib_type* getData() const { return *data; } /* ... */ /* Lots of functions for using the wrapped object */ }; 

Now for the concrete question: is this a good solution? Or are there other, perhaps better solutions?

I am particularly worried about the getData implementation; whether I should return a copy of the shared pointer or a naked pointer and why.

In my C++ project I am relying on some libraries that do memory management for me. I make wrapper classes, for ease of use and memory safety, for example the class below. Note that this is a much simplified example, to demonstrate my problem.

#include <library> class Wrapper { private: lib_type* data; public: Wrapper() : data(library_new()) { } Wrapper(const Wrapper& orig) = delete; ~Wrapper() { library_free(data); } const lib_type* getData() const { return data; } }; 

I needed to delete the copy constructor, because otherwise a copy going out of scope would invalidate the original object. Not being allowed to have copies makes the object very impractical to use - everywhere it is used I now need to hold a reference, and I need to manage the object centrally, which partially defeats the purpose of the wrapper class.

Possible solutions I have tried/thought of:

  • Copying the data. This is normally not an option though, because it is either not allowed by the library or the data is huge.
  • Move constructors. I tried solving the lack of a copy constructor by using a move constructor, but depending on the implementation, either this did not solve the problem or it became effectively a copy constructor, reintroducing the related problems.
  • Smart pointers. Then I realized it might be solved by using smart pointers to the wrapper instead of references, as this removes the need to maintain a central copy.
  • Wrapping a smart pointer. Or I could wrap a smart pointer to the data instead of a raw pointer. This makes the implementation of the wrapper a little bit more complicated, but also makes it easier to use, giving the classes using it a cleaner interface.

My attempt at the second smart pointer solution applied to the example above:

#include <library> class Deleter { public: void operator()(lib_type* p) const { library_free(p); } }; class Wrapper { private: shared_ptr<lib_type> data; public: Wrapper() : data(library_new(), Deleter()) { } Wrapper(const Wrapper& orig) : data(orig.data) { } ~Wrapper() { } const lib_type* getData() const { return *data; } }; 

Now for the concrete question: is this a good solution? Or are there other, perhaps better solutions?

I am particularly worried about the getData implementation; whether I should return a copy of the shared pointer or a naked pointer and why.

In my C++ project I am relying on some libraries that do memory management for me. I make wrapper classes, for ease of use and memory safety, for example the class below. Note that this is a much simplified example, to demonstrate my problem.

#include <library> class Wrapper { private: lib_type* data; public: Wrapper() : data(library_new()) { } Wrapper(const Wrapper& orig) = delete; ~Wrapper() { library_free(data); } const lib_type* getData() const { return data; }  /* ... */ /* Lots of functions for using the wrapped object */ }; 

I needed to delete the copy constructor, because otherwise a copy going out of scope would invalidate the original object. Not being allowed to have copies makes the object very impractical to use - everywhere it is used I now need to hold a reference, and I need to manage the object centrally, which partially defeats the purpose of the wrapper class.

Possible solutions I have tried/thought of:

  • Copying the data. This is normally not an option though, because it is either not allowed by the library or the data is huge.
  • Move constructors. I tried solving the lack of a copy constructor by using a move constructor, but depending on the implementation, either this did not solve the problem or it became effectively a copy constructor, reintroducing the related problems.
  • Smart pointers. Then I realized it might be solved by using smart pointers to the wrapper instead of references, as this removes the need to maintain a central copy.
  • Wrapping a smart pointer. Or I could wrap a smart pointer to the data instead of a raw pointer. This makes the implementation of the wrapper a little bit more complicated, but also makes it easier to use, giving the classes using it a cleaner interface.

My attempt at the second smart pointer solution applied to the example above:

#include <library> class Deleter { public: void operator()(lib_type* p) const { library_free(p); } }; class Wrapper { private: shared_ptr<lib_type> data; public: Wrapper() : data(library_new(), Deleter()) { } Wrapper(const Wrapper& orig) : data(orig.data) { } ~Wrapper() { } const lib_type* getData() const { return *data; } /* ... */ /* Lots of functions for using the wrapped object */ }; 

Now for the concrete question: is this a good solution? Or are there other, perhaps better solutions?

I am particularly worried about the getData implementation; whether I should return a copy of the shared pointer or a naked pointer and why.

added 88 characters in body
Source Link
Oebele
  • 215
  • 2
  • 9

In my C++ project I am relying on some libraries that do memory management for me. I make wrapper classes, for ease of use and memory safety, for example: the class below. Note that this is a much simplified example, to demonstrate my problem.

#include <library> class Wrapper { private: lib_type* data; public: Wrapper() : data(library_new()) { } Wrapper(const Wrapper& orig) = delete; ~Wrapper() { library_free(data); } const lib_type* getData() const { return data; } }; 

I needed to delete the copy constructor, because otherwise a copy going out of scope would invalidate the original object. Not being allowed to have copies makes the object very impractical to use - everywhere it is used I now need to hold a reference, and I need to manage the object centrally, which partially defeats the purpose of the wrapper class.

Possible solutions I have tried/thought of:

  • Copying the data. This is normally not an option though, because it is either not allowed by the library or the data is huge.
  • Move constructors. I tried solving the lack of a copy constructor by using a move constructor, but depending on the implementation, either this did not solve the problem or it became effectively a copy constructor, reintroducing the related problems.
  • Smart pointers. Then I realized it might be solved by using smart pointers to the wrapper instead of references, as this removes the need to maintain a central copy.
  • Wrapping a smart pointer. Or I could wrap a smart pointer to the data instead of a raw pointer. This makes the implementation of the wrapper a little bit more complicated, but also makes it easier to use, giving the classes using it a cleaner interface.

My attempt at the second smart pointer solution applied to the example above:

#include <library> class Deleter { public: void operator()(lib_type* p) const { library_free(p); } }; class Wrapper { private: shared_ptr<lib_type> data; public: Wrapper() : data(library_new(), Deleter()) { } Wrapper(const Wrapper& orig) : data(orig.data) { } ~Wrapper() { } const lib_type* getData() const { return *data; } }; 

Now for the concrete question: is this a good solution? Or are there other, perhaps better solutions?

I am particularly worried about the getData implementation; whether I should return a copy of the shared pointer or a naked pointer and why.

In my C++ project I am relying on some libraries that do memory management for me. I make wrapper classes, for ease of use and memory safety, for example:

#include <library> class Wrapper { private: lib_type* data; public: Wrapper() : data(library_new()) { } Wrapper(const Wrapper& orig) = delete; ~Wrapper() { library_free(data); } const lib_type* getData() const { return data; } }; 

I needed to delete the copy constructor, because otherwise a copy going out of scope would invalidate the original object. Not being allowed to have copies makes the object very impractical to use - everywhere it is used I now need to hold a reference, and I need to manage the object centrally, which partially defeats the purpose of the wrapper class.

Possible solutions I have tried/thought of:

  • Copying the data. This is normally not an option though, because it is either not allowed by the library or the data is huge.
  • Move constructors. I tried solving the lack of a copy constructor by using a move constructor, but depending on the implementation, either this did not solve the problem or it became effectively a copy constructor, reintroducing the related problems.
  • Smart pointers. Then I realized it might be solved by using smart pointers to the wrapper instead of references, as this removes the need to maintain a central copy.
  • Wrapping a smart pointer. Or I could wrap a smart pointer to the data instead of a raw pointer. This makes the implementation of the wrapper a little bit more complicated, but also makes it easier to use, giving the classes using it a cleaner interface.

My attempt at the second smart pointer solution applied to the example above:

#include <library> class Deleter { public: void operator()(lib_type* p) const { library_free(p); } }; class Wrapper { private: shared_ptr<lib_type> data; public: Wrapper() : data(library_new(), Deleter()) { } Wrapper(const Wrapper& orig) : data(orig.data) { } ~Wrapper() { } const lib_type* getData() const { return *data; } }; 

Now for the concrete question: is this a good solution? Or are there other, perhaps better solutions?

I am particularly worried about the getData implementation; whether I should return a copy of the shared pointer or a naked pointer and why.

In my C++ project I am relying on some libraries that do memory management for me. I make wrapper classes, for ease of use and memory safety, for example the class below. Note that this is a much simplified example, to demonstrate my problem.

#include <library> class Wrapper { private: lib_type* data; public: Wrapper() : data(library_new()) { } Wrapper(const Wrapper& orig) = delete; ~Wrapper() { library_free(data); } const lib_type* getData() const { return data; } }; 

I needed to delete the copy constructor, because otherwise a copy going out of scope would invalidate the original object. Not being allowed to have copies makes the object very impractical to use - everywhere it is used I now need to hold a reference, and I need to manage the object centrally, which partially defeats the purpose of the wrapper class.

Possible solutions I have tried/thought of:

  • Copying the data. This is normally not an option though, because it is either not allowed by the library or the data is huge.
  • Move constructors. I tried solving the lack of a copy constructor by using a move constructor, but depending on the implementation, either this did not solve the problem or it became effectively a copy constructor, reintroducing the related problems.
  • Smart pointers. Then I realized it might be solved by using smart pointers to the wrapper instead of references, as this removes the need to maintain a central copy.
  • Wrapping a smart pointer. Or I could wrap a smart pointer to the data instead of a raw pointer. This makes the implementation of the wrapper a little bit more complicated, but also makes it easier to use, giving the classes using it a cleaner interface.

My attempt at the second smart pointer solution applied to the example above:

#include <library> class Deleter { public: void operator()(lib_type* p) const { library_free(p); } }; class Wrapper { private: shared_ptr<lib_type> data; public: Wrapper() : data(library_new(), Deleter()) { } Wrapper(const Wrapper& orig) : data(orig.data) { } ~Wrapper() { } const lib_type* getData() const { return *data; } }; 

Now for the concrete question: is this a good solution? Or are there other, perhaps better solutions?

I am particularly worried about the getData implementation; whether I should return a copy of the shared pointer or a naked pointer and why.

Source Link
Oebele
  • 215
  • 2
  • 9
Loading