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());
}
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?
Let say I have this class design
class A {};
class B : public A {};
class C : public A {};
and a container of A like this
std::list<A *> elements;
Now what I want to achieve is iterate through all B objects in my container, or, in another time, iterate through all C objects.
The classic way would be
for (auto it = elements.begin(); it != elements.end(); ++it) {
B * b = dynamic_cast<B *>(*it);
if (b) {
// do stuff
}
}
One idea that comes to my mind is creating an iterator class derived from standard that filters but it would be difficult.
No limits on the c++ language level (c++20 may be ok as well but it would be great to see C++11 replies).
Plain c++ and stl please (I know boost has some foreach if construct but).
A possible c++20 implementation using range
#include <iostream>
#include <list>
#include <ranges>
struct A {
virtual ~A() = default;
};
struct B : public A {
void foo() const { std::cout << "B\n"; }
};
struct C : public A {};
int main() {
std::list<A *> demo{new A{}, new B{}, new C{}, new B{}};
auto is_B = [](const A *p) { return dynamic_cast<const B *>(p) != nullptr; };
auto get_B_const = [](const A *p) { return dynamic_cast<const B *>(p); };
for (auto p_B :
demo | std::views::filter(is_B) | std::views::transform(get_B_const)) {
p_B->foo();
}
// demo destruction with delete not shown
}
Prints:
B
B
Demo: https://godbolt.org/z/6oP8hj
Note: if performance matter you can avoid using dynamic_cast two times by
auto get_B_const = [](const A *p) {
assert(dynamic_cast<const B *>(p));
return static_cast<const B *>(p);
};
I can add 2 cents: normally this smells like a design flaw ( sure there are exceptions ), this problem of "heteroganeous container", does not have a "good" solution so far. Something I have seen in th wilds is that on top of std:vector<A*> va with all elements, you may maintain another vector only with "B*" objects, std::vector<B*> vb, when it´s time to iterate go for vb when it´s time to delete go for va
One of the possible solutions without dynamic_cast. But care should be taken to state the correct type in derived class constructors.
And I would recommend to use std::unique_ptr if the list actually stores the class objects.
class Base
{
public:
enum class Type
{
A,
B,
C
};
Base() = delete;
virtual ~Base() = default;
Type type() const { return _type; }
protected:
Base(Type type) : _type{type} {}
private:
Type _type;
};
class A : public Base
{
public:
A() : Base{Base::Type::A} {}
};
class B : public Base
{
public:
B() : Base{Base::Type::B} {}
};
class C : public Base
{
public:
C() : Base{Base::Type::C} {}
};
void function()
{
std::list<std::unique_ptr<Base>> list;
list.emplace_back(std::make_unique<A>());
list.emplace_back(std::make_unique<B>());
list.emplace_back(std::make_unique<C>());
// use non-const iterators if you intend to modify the object
std::for_each(std::cbegin(list), std::cend(list),
[](const auto &item)
{
switch (item->type())
{
case Base::Type::B:
{
assert(dynamic_cast<B*>(item.get()));
const auto &b = static_cast<B*>(item.get());
// do staff with b
break;
}
default:
return;
}
});
}
I think in C++11 the way you described is as close as it gets, but I may be wrong on this. C++17 greatly extended the algorithms library, so you could use std::for_each.
To demonstrate this, let's give the classes a little bit of functionality and create a vector (or list) of instances:
class A {
public:
virtual std::string name() const = 0;
};
class B : public A {
public:
virtual std::string name() const override {
return "Class B";
}
};
class C : public A {
public:
virtual std::string name() const override {
return "Class C";
}
};
int main()
{
std::vector<A*> vec { new B(), new B(), new C(), new C(), new B() };
}
Now using for_each, you could re-write your loop:
std::for_each(std::begin(vec), std::end(vec), [](const A* val) {
auto B* b = dynamic_cast<B*>(val);
if (b)
std::cout << b->name() << std::endl;
});
Unfortunately, there is no builtin filter for any of the algorithms. You could, however, implement something like for_each_if:
template<typename Iterator, typename Predicate, typename Operation> void
for_each_if(Iterator begin, Iterator end, Predicate pred, Operation op) {
std::for_each(begin, end, [&](const auto p) {
if (pred(p))
op(p);
});
}
And use it like this:
for_each_if(std::begin(vec), std::end(vec),
[](A* val) { return dynamic_cast<B*>(val) != nullptr; },
[](const A* val) {
std::cout << val->name() << std::endl;
}
);
Or for your specific case, you could specialize the implementation even more:
template<typename T, typename Iterator, typename Operation> void
dynamic_for_each(Iterator begin, Iterator end, Operation op) {
std::for_each(begin, end, [&](auto p) {
auto tp = dynamic_cast<T>(p);
if (tp)
op(tp);
});
}
and use it like so:
dynamic_for_each<B*>(std::begin(vec), std::end(vec), [](const B* val) {
std::cout << val->name() << std::endl;
});
All three implementations print the same output:
Class B
Class B
Class B
You do not need to cast if you got the design right:
struct A {
virtual void doSomethingWithB() = 0;
virtual ~A() = default;
};
struct B : A {
void doSomethingWithB() override {
// do somehting
}
};
struct C : A {
void doSomethingWithB() override {
// do nothing !
}
};
Then your loop is simply:
for (auto elem : elements) {
elem->doSomethingWithB();
}
In java you could have something like:
Map<Foo, List<Bar>> things;
for(Foo foo : things.getKeySet()){
List<bar> = things.get(foo);
}
Is there an equivalent for c++, maybe in std::map? Thanks for any help.
See std::map and std::vector (ArrayList) and maybe std::unordered_map (HashMap) and std::list (LinkedList)
For example:
#include <map>
#include <vector>
struct Foo {};
struct Bar {};
int main()
{
std::map<Foo, std::vector<Bar>> things;
for(auto& thing: things) {
const Foo& foo = thing.first; // key
std::vector<Bar>& bars = thing.second; // value
// use foo & bars here
}
}
Note: A std::map requires that a comparison operator be defined for user defined types like Foo:
struct Foo
{
int i = 0;
Foo(int i): i(i) {}
// need a comparison operator for ordered containers
bool operator<(const Foo& foo) const { return i < foo.i; }
};
I have vector of objects and a vector of criteria to filter by. Inspired by Moo-Juice from this post, I wrote such a code:
#include <algorithm>
#include <string>
#include <memory>
#include <vector>
struct Token {
char code;
int val;
Token(char c,int a) : code(c),val(a) {}
};
class FilterBase {
public:
virtual bool operator()(const std::shared_ptr<Token> p) =0;
};
class ByCode : public FilterBase {
public:
ByCode( char c) : code_(c) {}
virtual bool operator()(const std::shared_ptr<Token> p) {
return code_ == p->code;
}
private:
unsigned char code_;
};
int main() {
std::vector<std::shared_ptr<FilterBase>> filters;
filters.push_back(std::make_shared<ByCode>('A'));
filters.push_back(std::make_shared<ByCode>('B'));
std::shared_ptr<Token> p = std::make_shared<Token>('M', 20);
std::vector<std::shared_ptr<Token>> tokens;
tokens.push_back(p);
filters[0]->operator ()(p);
for (const std::shared_ptr<FilterBase> fi : filters) {
tokens.erase(std::remove_if(tokens.begin(), tokens.end(), *fi), tokens.end());
}
}
But unfortunately it does not compile, because parameter type 'FilterBase' is an abstract class. Well I know it is, I just thoght the virtual keyword would make it working...
Replace:
tokens.erase(std::remove_if(tokens.begin(), tokens.end(), *fi), tokens.end());
with:
tokens.erase(std::remove_if(tokens.begin(), tokens.end(), std::ref(*fi)), tokens.end());
remove_if takes its functor by-value, which causes your *fi to be sliced into an instance of the base class, which has a pure virtual object. Things go poorly.
std::ref has an overloaded operator() which should invoke the virtual operator() of *fi if MSVC didn't screw things up (for example, if it invokes the operator the wrong way).
If this fails, you can write your own adapter:
template<typename T>
struct callable_by_ref {
T* t;
template<typename... Args>
auto operator(Args&&...args) const ->
decltype( std::declval<T&>()(std::declval<Args&&>()...) )
{
return (*t)(std::forward<Args>(args)...);
}
};
template<typename T>
callable_by_ref< typename std::remove_reference<T>::type >
call_by_ref( T&& t ) {
return {&t};
}
which should solve your problem even if std::ref does not.
tokens.erase(std::remove_if(tokens.begin(), tokens.end(), call_by_ref(*fi)), tokens.end());
What I am doing:
The callable_by_ref is basically a quick perfect forwarder with a half-functional std::reference_wrapper implementation on top of it. call_by_ref does type deduction for you to create such an object.
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.