Cast directly in foreach loop - c++

In a certain situation I have an std::vector of pointers to ClassA. Another class, ClassB, inherits from ClassA. At some point I know this vector only contains pointers to instances of ClassB. I iterate over the vector with a foreach loop, after which I cast the object to ClassB.
Currently this looks similar to this:
Class ClassA
{
}
Class ClassB : public ClassA
{
public:
void DoSomething();
}
std::vector<ClassA*> vecA;
void iterate()
{
for(ClassA* obj : vecA)
{
((ClassB*)obj)->DoSomething();
}
}
I wonder if I can directly cast the object in the foreach loop. This would be shorter, and would not require me to cast the object every time I want to use it. I am looking for something that looks like this:
void iterate()
{
for((ClassB*)ClassA* obj : vecA)
{
obj->DoSomething();
}
}
Is this possible? And if it is not, what would be an easy way to 'save' the cast, if I want to use the casted object more than one time?
Thanks in advance.

void iterate() {
for(ClassA* obj_ : vecA) {
Assert(dynamic_cast<ClassB*>(obj_)); // debug build sanity check
auto* obj = static_cast<ClassB*>(obj_);
obj->DoSomething();
}
}

How about a container wrapper? Let's look at the usage first:
void iterate()
{
for (ClassB* obj : cast_range<ClassB*>(vecA))
{
obj->DoSomething();
}
}
And here is one possible implementation:
template<typename Target, typename Underlying>
struct cast_iterator_t
{
Underlying it;
Target operator*() const
{
return (Target) *it;
}
bool operator==(cast_iterator_t that) const
{
return it == that.it;
}
bool operator!=(cast_iterator_t that) const
{
return it != that.it;
}
cast_iterator_t& operator++()
{
++it;
return *this;
}
cast_iterator_t operator++(int)
{
cast_iterator_t old(*this);
++*this;
return old;
}
};
template<typename Target, typename Underlying>
cast_iterator_t<Target, Underlying> cast_iterator(Underlying it)
{
return {it};
}
template<typename Target, typename Range>
struct cast_range_t
{
Range& range;
decltype(cast_iterator<Target>(std::begin(range))) begin()
{
return cast_iterator<Target>(std::begin(range));
}
decltype(cast_iterator<Target>(std::end(range))) end()
{
return cast_iterator<Target>(std::end(range));
}
};
template<typename Target, typename Range>
cast_range_t<Target, Range> cast_range(Range& range)
{
return {range};
}

Related

c++ 11 segmentation fault (core dumped),but c++ 17 not

class all {
public:
template <typename T>
all(T&& t)
: data_ptr(new derived<T>(std::forward<T>(t))) {
}
all()
: data_ptr(nullptr) {}
all(const all& o)
: data_ptr(o.clone()) {}
all(const all&& o)
: data_ptr(o.clone()) {}
all& operator=(const all& o) {
auto n = o.clone();
if (data_ptr != nullptr) {
delete data_ptr;
}
data_ptr = n;
return *this;
}
all& operator=(all&& a)
{
if (data_ptr == a.data_ptr)
return *this;
swap(data_ptr, a.data_ptr);
return *this;
}
~all() {
if (data_ptr != nullptr) {
delete data_ptr;
}
}
template <typename U>
bool is() const {
auto ret = dynamic_cast<derived<U>*>(data_ptr);
return ret != nullptr;
}
template<typename U> U& as(){
auto ret = dynamic_cast<derived<U>*>(data_ptr);
if (ret==nullptr){
throw std::runtime_error("type dynamic_cast error");
}
return ret->value;
}
template<typename U>operator U(){
return as<U>();
}
private:
struct base {
virtual base* clone() = 0;
virtual ~base(){};
};
template <typename T>
struct derived : public base {
template <typename U>
derived(U&& v)
: value(std::forward<U>(v)) {
}
T value;
base* clone() {
return new derived<T>(value);
}
};
base* data_ptr;
base* clone() const {
if (data_ptr == nullptr) {
return nullptr;
} else {
return data_ptr->clone();
}
}
};
cmake compile options:
set (CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0 ")
test cases as follows:
int main(int argc, char const* argv[]) {
all at = 12;
cout << at.is<int>() << endl;
cout<<at.as<int>()<<endl;
cout<<int(at)<<endl;
return 0;
}
c++11,17 both compile successful,but c++ 11 throw segmentation fault when run ,c++17 run successful,why? i'm so frustrated,can someone help me?
Here is Complete Reproducible Example (not minimal).
all at = 12;
It seems that the conversion sequence is this:
A temporary object is constructed from the right hand expression, using the constructor all::all<int>(int&&).
That temporary object is used to initialise at.
Since the temporary all is non-const, the template constructor is a better match than all(const all&&).
Hence, all::all<all>(all&&) is invoked. This initialises a all::derived<all>::derived which has an all member that is initialised using all::all<all>(all&&) (because that is again, a better match than all::all(const all&&)), which invokes all::all(const all&&) which initialises all::derived<all>::derived which invokes all::all(const all&&) ... can you spot the pattern? The recursion never ends. You eventually get a stack overflow.
In C++17 at is initialised directly from the initialiser without involving a temporary object, so there is no stack overflow.
A simple fix is to add a move constructor:
all(all&& o) : data_ptr{std::exchange(o.data_ptr, nullptr)} {}
P.S. Avoid the use of bare owning pointers such as data_ptr. Use smart pointers such as std::unique_ptr instead.

Lambda that uses dynamic cast

Let's suppose that we have 3 classes:
class A
{
public:
int a;
virtual ~A() = default;
};
class B : public A
{
public:
int b;
};
class C : public A
{
public:
int c;
};
And a vector that contains polymorphic objects derived from A
std::vector<A*> objects;
I want to have a template method, that will return me an object from vector of type gived in template, if that object exists, but I don't know how to write it..
This not work:
template<typename ComponentType>
ComponentType * GetComponent()
{
bool pred = std::find_if(objects.begin(), objects.end(),
[=](A * obj)
{
return
dynamic_cast<ComponentType*>(obj) != nullptr;
});
return pred != objects.end();
}
I know that it could be done with that code:
template<typename ComponentType>
ComponentType * GetComponent()
{
for (item : objects)
{
auto casted = dynamic_cast<ComponentType*>(item);
if (casted)
return casted;
}
return nullptr;
}
But I want to use lambda.
It does not work at least because std::find_if returns an iterator, not a bool.
You might change your solution to fix it and return either a pointer to the element or nullptr if there is no such element:
template<typename ComponentType>
ComponentType * GetComponent()
{
auto it = std::find_if(objects.begin(), objects.end(),
[](A * obj)
{
return dynamic_cast<ComponentType*>(obj) != nullptr;
});
return it != objects.end()
? dynamic_cast<ComponentType*>(*it)
: nullptr;
}
Note, that it is better to avoid dynamic_cast at all if it is possible. For example, you might add a virtual method to A class which identifies an object somehow, then override it in B and C and use to find a requested object.

Using same template for regular pointer and shared pointer

This one does not work. I wanted to reuse the template that I made for regular pointer. How can I use the same template for std::shared_ptr
class Base
{
public:
int getVal() { return 0; }
};
template <class Type>
bool writeRecordForSet(std::vector<Type> entityPtr)
{
if (entityPtr.size() == 0) return true;
//...
for (auto iter = entityPtr.begin(); iter != entityPtr.end(); iter++) {
Type enPtr = *iter;
int myval = enPtr->getVal();
}
return true;
}
int main()
{
std::vector<std::shared_ptr<Base>> vec_shared;
std::vector<int*> vec_intp;
std::vector<std::unique_ptr<Base>> vec_unique_ptr;
writeRecordForSet(vec_shared);
writeRecordForSet(vec_intp);
writeRecordForSet(vec_unique_ptr);
}
You cannot copy a std::unique_ptr<>, nor a std::vector<std::unique_ptr<>>, so don't try that, but take the argument by reference (which you should to anyway; also use a range-based for loop for clarity)
template <class Type>
bool writeRecordForSet(std::vector<Type> const&entityPtr)
{
if (entityPtr.size() == 0) return true;
for(const auto&enPtr : entityPtr) {
auto myval = enPtr->getVal();
/* ... */
}
return true;
}
Of course, this will fail to compile if called for a Type that does not allow for Type::getVal() (such as your vector<int*> example). If you want your function to work for Types that don't have such a getter, you can use a getter adaptation, i.e.
template<typename T>
inline auto getVal(T const&x) { return T::getVal(); }
inline int getVal(int*x) { return *x; }
Problem 1
bool writeRecordForSet(std::vector<Type> entityPtr) { ... }
is a problem when the argument is of type std::unique_ptr since they cannot be copy constructed.
Change that to use a reference:
bool writeRecordForSet(std::vector<Type>& entityPtr) { ... }
or
bool writeRecordForSet(std::vector<Type> const& entityPtr) { ... }
Problem 2
In the function, you are assuming that the core object is of type Base.
for (auto iter = entityPtr.begin(); iter != entityPtr.end(); iter++) {
Type enPtr = *iter;
// Assuming that enPtr is a Base*, or shared_ptr<Base>, or unique_ptr<Base>
int myval = enPtr->getVal();
}
If you use
std::vector<Base*> vec_intp;
instead of
std::vector<int*> vec_intp;
it will work.
You can add getVal adaptor function to make it work and then write multiple overloads for your int*, shared_ptr<Base>, unique_ptr<Base>.
For example, getVal for int* could be as simple as:
int getVal(int*& p)
{
return *p;
}
And then your writeRecordForSet should call getVal to get int value.
Full example:
#include <vector>
#include <memory>
using namespace std;
class Base
{
public:
int getVal() { return 0; }
};
int getVal(shared_ptr<Base>& p)
{
return p->getVal();
}
int getVal(unique_ptr<Base>& p)
{
return p->getVal();
}
int getVal(int*& p)
{
return *p;
}
template <class Type>
bool writeRecordForSet(std::vector<Type>& entityPtr)
{
if (entityPtr.size() == 0)
return true;
//...
for (auto iter = entityPtr.begin(); iter != entityPtr.end(); iter++) {
int myval = getVal(*iter);
}
return true;
}
int main()
{
std::vector<std::shared_ptr<Base>> vec_shared;
std::vector<int*> vec_intp;
std::vector<std::unique_ptr<Base>> vec_unique_ptr;
writeRecordForSet(vec_shared);
writeRecordForSet(vec_intp);
writeRecordForSet(vec_unique_ptr);
}

Custom container range-based iteration

I have a custom container which I want to use in a ranged-based for loop. The container is somewhat based on a vector, like this:
template<typename T>
class IDMap
{
private:
struct Item {
uint16_t mVersion;
T mItem;
template <typename... Arguments>
Item(uint16_t version, Arguments&&... args) : mVersion(version), mItem(args...)
{
}
};
public:
typedef uint32_t ItemID;
template <typename... Arguments>
ItemID AddItem(Arguments&&... args);
void MarkAsFree(const ItemID id);
T& GetItem(const ItemID id);
T* TryGetItem(const ItemID id);
void Clear();
private:
std::vector<Item> mItems;
std::vector<uint16_t> mFreeIndices;
};
I want to iterate the mItems vector, but only return the mItem member rather than the entire Item struct. Is there any easy/elegant way to do this?
You have to provide a begin and end function, both returning a corresponding iterator, which itself implements operators ++, != and *. The begin and end functions can be free-standing or as members.
Start with implementing an iterator which has the behavior you want. You can implement it as a wrapper around a std::vector::iterator to save most of the "core" work.
The following is untested code
Basically, inside class IDMap, add:
class ItemIterator {
// based on vector iterator
std::vector<Item>::iterator i;
public:
ItemIterator(std::vector<Item>::iterator i) : i(i) {}
// incrementing
ItemIterator & operator ++() { ++i; return *this; }
ItemIterator operator ++(int) { const_iterator old(*this); ++(*this); return old; }
// comparison
bool operator!=(const ItemIterator &o) const { return i != o.i; }
// dereferencing
const T & operator*() const { return i->mItem; }
};
using iterator = ItemIterator;
using value_type = T;
ItemIterator begin() const { return ItemIterator(mItems.begin()); }
ItemIterator end() const { return ItemIterator(mItems.end() ); }
If you ever want to support multiple kinds of "special iteration" over your IDMap, like for example also over the indices, or over the "whole" Items, you should wrap everything above in another adaptor. This adaptor can then be accessed with a member method, like .items().
Brief example:
class IDMap {
// (your code)
public:
struct ItemsAdaptor {
// (insert above iterator definition + usings)
ItemsAdaptor(std::vector<Item>::iterator b,
std::vector<Item>::iterator e)
: b{b}, e{e}
{}
ItemIterator begin() const { return b; }
ItemIterator end() const { return e; }
private:
ItemIterator b, e;
};
ItemsAdaptor items() const {
return ItemsAdaptor(mItems.begin(), mItems.end());
}
};
Then, you can write:
IDMap<int> map = ...;
for (int i : map.items()) {
...
}
If you want the range-based for to work for your container, you have to provide begin and end functions that return forward iterators.
typedef std::vector<Item>::iterator iterator;
typedef std::vector<Item>::const_iterator const_iterator;
iterator begin()
{
return mItems.begin();
}
const_iterator begin() const;
{
return mItems.begin();
}
//also add end functions, and viola.
This will return the whole item struct. If you have to only return mItem, you'll have to write your own iterator adaptor and use it instead of vector's.

Iterating over vectors of type Base and/or types derived from base

I need to store objects of type Base, and of the derived types BaseDerivedA and BaseDerivedB. These objects need to be aligned in memory. I want to provide an iterator that iterates over all the objects. I'd like to avoid the memory overhead of storing a vector of Base pointers.
For this purpose I've built the following container
struct Container {
std::vector<Base> bases;
std::vector<BaseDerivedA> derivedAs;
std::vector<BaseDerivedB> derivedBs;
// Iterator over the three vectors
all_iterator<Base> all_begin(){ return all_iterator(bases[0],this); }
all_iterator<Base> end_begin(){ return all_iterator(nullptr,this); }
// Where all_iterator is defined as
template < class T >
struct all_iterator
: public boost::iterator_facade< all_iterator<T>,
T, boost::forward_traversal_tag>
{
all_iterator() : it_(0) {}
explicit all_iterator(T* p, Container* c) // THIS JUST FEELS WRONG
: it_(p), c_(c) { }
private:
friend class boost::iterator_core_access;
T* it_;
Container* c_;
void increment() {
if (it_ == static_cast<T*>(&(c_->bases[c_->bases.size()-1]))) {
it_ = static_cast<T*>(&(c_->derivedAs[0]));
} else if (it_ == static_cast<T*>(&(c_->derivedAs[ds_->derivedAs.size()-1]))) {
it_ = static_cast<T*>(&(c_->derivedBs[0]));
} else if (it_ == static_cast<T*>(&(c_->derivedBs[ds_->derivedBs.size()-1]))) {
it_ = nullptr; // THIS DOES ALSO FEEL WRONG
} else {
++it_;
}
}
bool equal(all_iterator const& other) const {
return this->it_ == static_cast<T*>(other.it_);
}
T& dereference() const { return *it_; }
};
I am using a nullptr as the one-past-the-end iterator as well as a lot of cast. I am also passing my iterator a pointer to the data structure.
Is it there a better way of iterating over three vectors containing the type Base or types derived from base?
First we should note that your code has undefined behavior if bases is empty, or for any size of derivedBs if end_begin is called.
Is there a reason you can't that the more obvious and normal approach of having BaseType* or a smart variant in a single container, and using the abstract interface to access it, instead of that dynamic_cast/static_cast chain? Then the problem just goes away completely.
EDIT: If you need the memory of each type to be contiguous for some reason, and you don't do single inserts into the container frequently, just create a container of BaseType pointers that point to each object inside the derived object container(s). But I'd ask you to step back a moment and review why you need the objects to be contiguous (there could easily be a legitimate reason).
I assume that BaseType is the common base of both DerivedA and DerivedB and you want to have a container that contains instances of DerivedA and DerivedB and gives you the capability to iterator over all DerivedA-instances, over all DerivedB-instances and over all instances of BaseType (i.e. the union of DerivedA's and DerivedB's). You could do that like this:
class BaseType
{
public:
virtual void doit() const = 0;
virtual ~BaseType() { }
};
class DerivedA : public BaseType
{
public:
void doit() const { std::cout << "DerivedA::doit()" << std::endl; }
void a() const { std::cout << "DerivedA::a()" << std::endl; }
};
class DerivedB : public BaseType
{
public:
void doit() const { std::cout << "DerivedB::doit()" << std::endl; }
void b() const { std::cout << "DerivedB::b()" << std::endl; }
};
class Container
{
public:
void insert(DerivedA const & a)
{
m_as.push_back(a);
m_base.push_back(&m_as.back());
}
void insert(DerivedB const & b)
{
m_bs.push_back(b);
m_base.push_back(&m_bs.back());
}
std::vector<DerivedA>::iterator begin_a() { return m_as.begin(); }
std::vector<DerivedA>::iterator end_a() { return m_as.end(); }
std::vector<DerivedB>::iterator begin_b() { return m_bs.begin(); }
std::vector<DerivedB>::iterator end_b() { return m_bs.end(); }
std::vector<BaseType *>::iterator begin_all() { return m_base.begin(); }
std::vector<BaseType *>::iterator end_all() { return m_base.end(); }
protected:
private:
std::vector<DerivedA> m_as;
std::vector<DerivedB> m_bs;
std::vector<BaseType *> m_base;
};
For your iterator to be correct, you are going to have to know which vector you are currently traversing so that you can compare it properly. You can do this by having an enumeration which tells you which one is current:
void all_iterator::increment()
{
switch (current_member) {
case BasesMember:
++bases_iter;
if (bases_iter==bases.end()) {
current_member = DerivedAsMember;
}
return;
case DerivedAsMember:
++derived_as_iter;
if (derived_as_iter==derivedAs.end()) {
current_member = DerivedBsMember;
}
return;
case DerivedBsMember:
++derived_bs_iter;
if (derived_bs_iter==derivedBs.end()) {
current_member = EndMember;
}
return;
case EndMember:
assert(current_member!=EndMember);
break;
}
}
bool all_iterator::equal(all_iterator const &other) const
{
if (current_member!=other.current_member) return false;
switch (current_member) {
case BasesMember:
return bases_iter==other.bases_iter;
break;
case DerivedAsMember:
return derived_as_iter==other.derived_as_iter;
break;
case DerivedBsMember:
return derived_bs_iter==other.derived_bs_iter;
break;
case EndMember:
return true
}
}
Base& all_iterator::dereference() const
{
switch (current_member) {
case BasesMember: return *bases_iter;
case DerivedAsMember: return *derived_as_iter;
case DerivedBsMember: return *derived_bs_iter;
case EndMember:
assert(current_member!=EndMember);
break;
}
return *bases_iter;
}
Why would it matter what is located at derivedAs.end()? You will never access/modify it through derivedAs. So you don't need that assumption at all.
Typical code would be
for(auto it = derivedAs.begin(); it != derivedAs.end(); ++it) {
*it = // do whatever, will never do *derivedAs.end()
}