I have a class where the constructor takes parameter as reference. For eg.
class A
{
A(Tracer& t) : m_t(t) { }
private:
Tracer& m_t;
};
I have this class A as boost::optional and want to construct it only when needed. If I use boost::in_place to construct it. Since boost::in_place takes the parameters as const_refs, I had to modify the signature of the constructor to
A(const Tracer& t) : m_t(const_cast<Tracer&>(t) { }
is there any other way of passing the object by reference ?
The s/w limitation is boost 1.4.3, VS2010.
EDIT: The class is not copy-constructible and assignable as well. I haven't showed that in the sample class mentioned above.
Like this:
#include <boost/optional.hpp>
#include <boost/ref.hpp>
struct Tracer
{
Tracer() = default;
Tracer(const Tracer&) = delete;
Tracer(Tracer&&) = delete;
Tracer& operator=(const Tracer&) = delete;
Tracer& operator=(Tracer&&) = delete;
};
class A
{
public: // Note: I had to add this.
A(Tracer& t) : m_t(t) { }
private:
Tracer& m_t;
};
int main()
{
Tracer tracer;
boost::optional<A> x;
x = boost::in_place(boost::ref(tracer));
}
boost::ref returns a boost::reference_wrapper, which models a reference as a value.
Related
I want to write a class that uses the PIMPL idiom but makes the following possible:
int main() {
MyClass myclass {12};
std::string val = myclass.get_value();
std::cout << val << "\n";
MyClass copy = myclass;
val = copy.get_value();
return 0;
}
That is, provide copy functionality while using PIMPL. Using std::unique_ptr to implement PIMPL leads to the expected compile error:
error C2280: 'MyClass::MyClass(const MyClass &)': attempting to reference a deleted function
This is my attempt:
class.hpp
#pragma once
#include <string>
#include "copyable_unique_ptr.hpp"
class MyClass {
private:
struct MyClassPrivate;
copyable_unique_ptr<MyClassPrivate> _impl;
public:
MyClass(int value);
~MyClass();
std::string get_value();
};
class.cpp
#include "class.hpp"
#include <string>
struct MyClass::MyClassPrivate {
int value;
};
MyClass::MyClass(int value)
: _impl(std::make_unique<MyClassPrivate>()) {
_impl->value = value;
}
MyClass::~MyClass() = default;
std::string MyClass::get_value() {
return std::to_string(_impl->value);
}
copyable_unique_ptr.hpp
#pragma once
#include <memory>
template <typename T>
class copyable_unique_ptr {
private:
std::unique_ptr<T> _ptr;
public:
copyable_unique_ptr(std::unique_ptr<T> &&ptr)
: _ptr(std::move(ptr)) {}
~copyable_unique_ptr() = default;
copyable_unique_ptr(const copyable_unique_ptr<T> &other) {
_ptr = std::make_unique<T>(*other._ptr);
}
copyable_unique_ptr(copyable_unique_ptr<T> &&other) {
_ptr = std::move(other._ptr);
}
copyable_unique_ptr &operator=(const copyable_unique_ptr<T> &other) {
_ptr = std::make_unique<T>(*other._ptr);
}
copyable_unique_ptr &operator=(copyable_unique_ptr<T> &&other) {
_ptr = std::move(other._ptr);
}
T *operator->() {
return _ptr.get();
}
};
which leads to the following error:
warning C4150: deletion of pointer to incomplete type 'MyClass::MyClassPrivate'; no destructor called
I also had this error when first trying to use unique_ptr, and the solution was to move the destructor into class.cpp: MyClass::~MyClass() = default;.
I don't really know how to solve this problem while using the approach with copyable_unique_ptr.
I saw this question on SO. They are trying to do the same as me, but the last comment to the answer suggests that they are having exactly the same problem.
Although you can write a custom smart pointer here, I always like to reuse as much code as possible. It seems you want a dynamically created object with copy semantics rather than pointer semantics. For that reason I would hesitate to call your copyable_unique_ptr a pointer at all. I did write a class for this once and settled on something like dynamic_object<T>.
Instead of a pointer I would do this using a std::vector that contains just a single element. Something a bit like this:
class MyClass {
private:
struct MyClassPrivate;
std::vector<MyClassPrivate> _impl;
public:
MyClass(int value);
~MyClass();
std::string get_value();
};
struct MyClass::MyClassPrivate {
int value;
};
MyClass::MyClass(int value)
: _impl(1) {
_impl.front().value = value;
}
MyClass::~MyClass() = default;
std::string MyClass::get_value() {
return std::to_string(_impl.front().value);
}
However if you really want to create your copyable_unique_ptr I woud still use a std::vector here to simplify its codeing and to reuse high quality Standard Library code:
Perhaps a bit like this:
template<typename T>
class copyable_unique_ptr
: private std::vector<T>
{
using base_type = std::vector<T>;
public:
copyable_unique_ptr(std::unique_ptr<T>&& ptr)
: base_type(std::move(*ptr), 1) {}
copyable_unique_ptr(std::unique_ptr<T> const& ptr)
: base_type(*ptr, 1) {}
T& operator*() { return base_type::back(); }
T* operator->() { return base_type::data(); }
T const& operator*() const { return base_type::back(); }
T const* operator->() const { return base_type::data(); }
};
Sam Varshavchik gave a hint in the comment that also moving copy constructor and assignment operator to the implementation fixes the code that I was trying to write, that means:
class.hpp
#pragma once
#include <string>
#include "copyable_unique_ptr.hpp"
class MyClass {
private:
struct MyClassPrivate;
copyable_unique_ptr<MyClassPrivate> _impl;
public:
MyClass(int value);
MyClass(const MyClass &);
MyClass(MyClass &&);
MyClass &operator=(const MyClass &);
MyClass &operator=(MyClass &&);
~MyClass();
std::string get_value();
};
class.cpp
#include "class.hpp"
#include <string>
#include <iostream>
struct MyClass::MyClassPrivate {
int value;
};
MyClass::MyClass(int value)
: _impl(std::make_unique<MyClassPrivate>()) {
_impl->value = value;
}
MyClass::MyClass(const MyClass &) = default;
MyClass::MyClass(MyClass &&) = default;
MyClass &MyClass::operator=(const MyClass &) = default;
MyClass &MyClass::operator=(MyClass &&) = default;
MyClass::~MyClass() = default;
std::string MyClass::get_value() {
std::cout << &_impl << "\n";
return std::to_string(_impl->value);
}
And it works as expected.
On the other hand, Galik gave an answer that gives a much better and less complex alternative to copyable_unique_ptr. I will prefer using his way.
Its probably simpler to stick to a normal unique_ptr and just implement copying of MyClass in your cpp file:
class MyClass {
private:
struct MyClassPrivate;
std::unique_ptr<MyClassPrivate> _impl;
public:
MyClass(int value);
MyClass(MyClass&&);
MyClass(const MyClass&);
~MyClass();
MyClass& operator = (const MyClass&);
MyClass& operator = (MyClass&&);
std::string get_value();
};
MyClass::MyClass(const MyClass& other)
: _impl(std::make_unique<MyClassPrivate>(*other._impl)) {
}
MyClass& MyClass::operator = (const MyClass& other) {
_impl = std::make_unique<MyClassPrivate>(*other._impl);
return *this;
}
MyClass::~MyClass() = default;
MyClass::MyClass(MyClass&&) = default;
MyClass& MyClass::operator = (MyClass&&) = default;
There is a slight issue with this code (and your original code) in that the moved from objects will have a null _impl you might want to add checks for null, alternatively you could replace with a default constructed object instead of a null pointer but that might be a waste in most cases?
In C++ I can do
class A
{
public:
A(std::vector<std::unique_ptr<int>> v) : _v(std::move(v)) {}
private:
std::vector<std::unique_ptr<int>> _v;
}
How can I achieve something similar with ue4 types (TArray, TUniquePtr), i.e. how to move the contents of TArray?
Complete example:
#include <cassert>
#include <memory>
#include <vector>
class MyObj {};
class A {
public:
A(std::vector<std::unique_ptr<MyObj>> v) : _v(std::move(v)) {}
auto GetV() { return _v.front().get(); }
private:
std::vector<std::unique_ptr<MyObj>> _v;
};
int main() {
auto v = std::vector<std::unique_ptr<MyObj>>();
v.push_back(std::make_unique<MyObj>());
A a(std::move(v));
assert(a.GetV());
}
TArray has a move constructor (i.e., a constructor whose signature is TArray(TArray &&other)) as can be seen here.
So std::move should work on TArray the same way as it does on std::vector.
To complete the answer of Brennan:
C++ std -> UE4 equivalent:
std::vector -> TArray
std::unique_ptr -> TUniquePtr
std::make_unique -> MakeUnique
std::move -> MoveTempIfPossible (use MoveTemp to get compile time checks for rvalues and const)
So the code example from above with native UE4 classes would look like
class MyObj {};
class A {
public:
A(TArray<TUniquePtr<MyObj>> v) : _v(MoveTemp(v)) {}
auto GetV() { return _v[0].Get(); }
private:
TArray<TUniquePtr<MyObj>> _v;
};
int main() {
auto o = MyObj{};
auto v = TArray<TUniquePtr<MyObj>>();
v.Add(MakeUnique<MyObj>(o));
A a(MoveTemp(v));
assert(a.GetV());
}
How can I delete all the pointer in my vector before that I going to copy to my vector new pointers (in case of const object)?
class Element {
int val;
public:
Element(int val) :
val(val) {
}
};
class MyClass {
vector<Element*> v;
static void FreeMemory(vector<Element*>& vec) {
for (unsigned int i = 0; i < vec.size(); i++) {
delete vec[i];
}
}
public:
MyClass() = default;
MyClass(const MyClass& mc) {
//...
}
MyClass& operator=(const MyClass& mc) {
if (this == &mc) {
return *this;
}
//...
FreeMemory(mc.v); //**error** - how can I delete the memory of any Element?
//...
return *this;
}
// ....
// ....
};
binding 'const std::vector' to reference of type 'std::vector&' discards qualifiers
Can I fix it with smart_pointers?
Here is a sketch of a class owning a std::vector of Element objects managed by std::unique_ptr. Not fully worked out, but it might work as a starting point.
class Element {
int val;
public:
explicit Element(int val) : val(val) {}
virtual ~Element() = default;
/* Subclasses must implement this method: */
virtual std::unique_ptr<Element> clone() const = 0;
};
class ExclusivelyOwning {
private:
std::vector<std::unique_ptr<Element>> v;
public:
ExclusivelyOwning() = default;
ExclusivelyOwning(const ExclusivelyOwning& other) {
v.reserve(other.v.size());
for (const auto& element : other.v)
v.push_back(element->clone());
}
ExclusivelyOwning& operator=(const ExclusivelyOwning& rhs) {
/* Use copy-swap idiom, not shown here. */
return *this;
}
ExclusivelyOwning(ExclusivelyOwning&&) = default;
ExclusivelyOwning& operator = (ExclusivelyOwning&&) = default;
~ExclusivelyOwning() = default;
};
Note that copying an object with references to abstract classes (as Element in the code above) requires further techniques to render the copying meaningful. Here, I used a "virtual constructor" - the clone method.
Say I have a vector of ints
std::vector<int16_t> samples;
Is there a nice way to disable copying into this vector so that only moving is allowed? I know about std::move, but I'd like something like a compile error (like unique_ptr) if copying is attempted, rather than just relying on the programmer to "do the right thing"(tm)
Make an uncopyable wrapper:
#include <vector>
template<typename T>
class uncopyable
{
public:
uncopyable(const uncopyable&) = delete;
uncopyable(uncopyable&&) = default;
uncopyable(T&& data)
:
data_(std::move(data))
{
}
public:
uncopyable& operator=(const uncopyable&) = delete;
uncopyable& operator=(uncopyable&&) = default;
uncopyable& operator=(T&& data)
{
data_ = std::move(data);
return *this;
}
private:
T data_;
};
int main()
{
std::vector<int> big(10000);
uncopyable<std::vector<int>> uncopyable_big(std::move(big));
std::vector<int> other_big(10000);
uncopyable_big = std::move(other_big);
}
And use this type instead of your vectorif you want to guarantee no copies are made.
If it's a class member, then just make it private and only allow access in the ways you want:
std::vector<int16_t> const & get_samples() {return samples;}
void set_samples(std::vector<int16_t> && s) {samples = std::move(s);}
Otherwise, there's not much you can do to enforce particular access patterns.
I have the following (very simplified) "container" class:
class container
{
public:
template<typename T> container(const boost::shared_ptr<T> &rhs)
: m_content(rhs) { }
template<typename T>
operator T const & () const
{
return get<T>();
}
template<typename T>
T const & get() const
{
return *boost::any_cast< boost::shared_ptr<T> >(m_content);
}
private:
boost::any m_content;
};
It should store objects in the boost::any container in the form of a shared pointer. If I store some object, say, of the boost::shared_ptr<some_type> type in the container, I would like to get the reference (const some_type&) simply by a user-defined conversion which would allow to do something like this:
boost::shared_ptr<some_type> x(new some_type);
container cx = x;
...
// user-defined conversion
const some_type &y = cx;
// a template conversion using a "getter"
const some_type &y = cx.get<some_type>();
Sometimes, I need to store objects derived from some abstract type and do the same sort of type conversion to the reference of this abstract type, for example, like this:
boost::shared_ptr<some_abstract_type> x(new some_derived_type);
container cx = x;
...
// user-defined conversion
const some_abstract_type &y = cx;
// a template conversion using a "getter"
const some_abstract_type &y = cx.get<some_abstract_type>();
Both the user-defined conversion and the template "getter" work fine with GCC. However, the Intel C++ compiler seems to have a problem with the (user-defined) conversion while the "getter" works.
For example, the following code works with GCC but not with Intel:
#include <iostream>
#include <boost/any.hpp>
#include <boost/shared_ptr.hpp>
class container
{
public:
template<typename T> container(const boost::shared_ptr<T> &rhs)
: m_content(rhs) { }
template<typename T>
operator T const & () const
{
return get<T>();
}
template<typename T>
T const & get() const
{
return *boost::any_cast< boost::shared_ptr<T> >(m_content);
}
private:
boost::any m_content;
};
class base
{
public:
virtual ~base() { }
virtual void f() const = 0;
};
class derived : public base
{
public:
virtual ~derived() { }
virtual void f() const { std::cout << "hello\n"; }
};
void foo(const container &c)
{
const base & a = c;
a.f();
}
int main()
{
boost::shared_ptr<base> a(new derived);
container c = a;
foo(c);
}
With Intel, I get this error:
test.cpp(44): error: no suitable user-defined conversion from "const container" to "const base" exists
const base & a = c;
^
compilation aborted for test.cpp (code 2)
On the other hand, if I replace base with derived in both main() and foo() (or use the "getter" instead of the type conversion in foo()), everything works fine with Intel too. Is it possible to convince the Intel compiler to use the user-defined type conversion to the reference type when T is an abstract class?
Thanks in advance for any ideas.
EDIT: Interestingly, using the type conversion to the pointer type works fine. If I add
template<typename T>
operator T const * () const
{
return &get<T>();
}
to the container class and replace foo() with
void foo(const container &c)
{
const base * a = c;
a->f();
}
then it works also with Intel.
I would return a pointer in the getter:
template<typename T>
T const * get() const {
return boost::any_cast< boost::shared_ptr<T> >(m_content);
}
This avoids the conversion problem, and does not crash immediately if you pass a null pointer to your container.
Example:
void foo(const container &c)
{
const base* a = c.get<base>();
a->f();
}
You could also add a function valid() which checks if there is something in the container:
bool valid() const {
return m_content != NULL;
}
Edit: Your addition to your question follows exactly in this direction.
Ok, so it seems that it is a bug in the Intel C++ compiler and was filed in the bug tracking list.