I would like to know if there is a way in C++ to know in what data structure an address is. For example, I have a base class (A) that has two inherited class (B and C). In a fourth class (D), I have two vectors of the STL, one containing pointers of B, the second containing pointers of C.
In D, I am implementing a method that is withdrawing an object A. In that method, I am using another implemented function of D that is searching in the vectors if the object A is there and return a pointer to this object.
Is there a way after that to manipulate the appropriate vector of where the object A to directly delete it from the vector (knowing in what vector it is and its position in the vector) ?
A* D::findA(string word)
{
for (unsigned int i = 0; i < vectorOfB_.size(); i++) {
if ( vectorOfB_[i]->getWord() == word)
return vectorOfB_[i];
}
for (unsigned int i = 0; i < vectorOfC_.size(); i++) {
if (vectorOfC_[i]->getWord() == word)
return vectorOfC_[i];
}
bool D::withdrawA(string word)
{
A* obj = findA(word);
if (obj != nullptr) {
}
return false;
}
At this point, I know that the method found the object A, I know its address, but I don't know in what vector it is. I would like to use the erased() method of the STL vector class to withdraw it from the vector, but without doing loops again to go check in the vectors.
I guess you could use dynamic_cast to determine if the pointer of A is of type B or C.
bool D::withdrawA(string word)
{
A* obj = findA(word);
if (obj != nullptr) {
if(dynamic_cast<B*>(obj) != nullptr) {
// do something here for the B vector
}
else if(dynamic_cast<C*>(obj) != nullptr)
{
// do something here for the C vector
}
}
return false;
}
Since you are querying a member of the class (word) in order to identify the object, I don't think you need some maginc machanism to achive what you want.
You can use the STL algorithms for that, for instance having the classes:
#include <memory>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
class A {
public:
A(string word = "") :m_word(word){}
virtual inline string getWord() { return m_word; }
protected:
string m_word;
};
class B : public A {
public:
B(string word = "") : A(word) {}
};
class C : public A {
public:
C(string word = "") : A(word) {}
};
typedef shared_ptr<A> a_ptr;
typedef vector<a_ptr> a_vector;
You can write a function:
a_ptr find_A(a_vector v, string word, bool erase = false){
// Find the element.
auto it = find_if(v.cbegin(), v.cend(),
[word](const a_ptr &elem) {
return elem->getWord() == word;
}
);
// If you want to erase and it was found.
// The code below can be implemented in a more elegant way, but
// for that your classes will require you overload < operator and == operator.
if (erase && it != v.end()) {
v.erase(remove_if(v.begin(), v.end(),
[word](a_ptr elem){
return elem->getWord() == word;
}
), v.end());
}
return *it
}
Now you an use that function with both vectors.
A more specific example.
You can use STL algorithms in order to erase from your vectors too:
Suppose you have found some A*
A* a_ptr = findA(word);
Then you can use STL erase, remove_if idiom:
vectorOfB_.erase(remove_if(vectorOfB_.begin(), vectorOfB_.end(),
[a_ptr](A* elem){
return elem->getWord() == a_ptr->getWord();
}
), vectorOfB_.end());
vectorOfC_.erase(remove_if(vectorOfC_.begin(), vectorOfC_.end(),
[a_ptr](A* elem){
return elem->getWord() == a_ptr->getWord();
}
), vectorOfC_.end());
In C++, there is no way to directly know the data structure by an address.
Related
I have a class A with a member vector<class B>. I would like to loop through this vector from outside class A in a clean way. I need to do operations on B using its public functions.
To do so, I thought of having a function int get_next_element(B * in_B), where I can return 0 if I have correctly loaded the next element and -1 otherwise.
I thought of doing this by using an iterator, but I found two issues with this. First of all, I wasn't able to find a neat way to convert an iterator to a pointer (it seems I could use an iterator just like a pointer, but I'm unsure that's a good solution). Secondly, I would need to check if there's a value referenced by my iterator, and since the closest thing to a "null iterator" is the .end() element I can't figure out how I would then initialise it. If I initialise it (empty) and have the reference .end(), it wont refer to anything comparable if I add something to it.
I could have an extra int that keeps track of which element I'm at, but then I'd have to manage that int whenever I add elements, etc.
I considered placing the iteration code outside of class A, but I may need to change or access individual elements during the loop, so that would make a complex/big iteration block.
How would I solve this problem in a clean way (such as int get_next_element(B * in_b))?
EDIT:
Here's some code:
Header:
class B {
public:
B();
void set_size(int in_size);
int get_size();
protected:
int mSize;
};
class A {
public:
A();
void add_B(B in_B);
int get_next_element(B * in_B);
protected:
std::vector<B> mObjects;
};
cpp file:
B::B() {
// Stuff
}
void B::set_size(int in_size) {
mSize = in_size;
}
int B::get_size() {
return mSize;
}
A::A() {
// Stuff
}
void A::add_B(B in_B) {
mObjects.push_back(in_B);
}
int A::get_next_element(B * in_B) {
// ToDo : handle elements
}
And main:
int main() {
A test_a;
for (int i = 0; i < 5; i++) {
B tmp_b;
tmp_b.set_size(i);
test_a.add_B(tmp_b);
}
B iterator_b;
while (0 == get_next_element(& iterator_b)) {
if (iterator_b.get_size > 2) {
B tmp_b;
tmp_b.set_size(iterator_b.get_size - 2);
test_a.add_B(tmp_b);
iterator_b.set_size(2);
}
}
}
So, basically A holds a bunch of Bs and can help the main iterate through them and (in this example) cut them into smaller pieces while not having too much code in the main. There's quite a few dimensions/ways this will be done, which is partially why I'd like to "hide" as much of the code in A.
(This is a bit simplified, like the Bs may have to have internal relations, but basically that's the idea)
Consider using a range-base for loop (C++1x).
class A {
private:
std::vector<class B> vec;
public:
std::vector<class B>& get_vec() { return vec; }
};
A a_instance;
for (B &b : a_instance.get_vec()) {
b.print();
std::cout << "b = " << b << std::endl;
std::cout << "&b = " << &b << std::endl;
}
This, unfortunately, does not allow looking ahead, unless you keep track of index yourself.
this is what I mean...
#include <iostream>
#include <vector>
class B {
public:
B(int in) :mSize(in) {}
size_t mSize;
void set_size(int in_size) { mSize = in_size;}
int get_size() {return mSize;}
};
class A {
using container = std::vector<B>;
using iterator = container::iterator;
container mObjects;
public:
void add_B(B in_B) { mObjects.push_back(in_B); }
iterator begin() { return mObjects.begin(); }
iterator end() { return mObjects.end(); }
};
int main() {
A test_a;
for (int i = 0; i < 5; i++) {
test_a.add_B(B(i));
}
for( auto& item : test_a)
if (item.get_size() > 2) {
B tmp_b(item.get_size() - 2);
item.set_size(2);
test_a.add_B(tmp_b);
break;//if using a vector, must break as vector can change/reallocate on 'add_B()'
}
}
I've written a little toy data model, which uses a std::set to unique instances. This may be called either the flyweight pattern, or hash-consing (though, technically, I'm not yet using a hash table).
#include <set>
#include <cassert>
enum Color { Red, Green, Blue };
struct Shape {
// Set the color, return a new shape.
virtual const Shape* color(Color) const = 0;
};
template<class T>
const T* make_shape(T value) {
struct cmp {
bool operator()(const T* a, const T* b) const {
return *a < *b;
}
};
static std::set<const T*, cmp > values;
auto iter = values.find(&value);
if(iter != values.end()) {
return *iter;
}
auto p = new T(value);
values.insert(p);
return p;
}
struct Circle : public Shape {
Color c = Red;
virtual const Shape* color(Color c) const {
Circle r;
r.c = c;
return make_shape(r);
}
bool operator<(const Circle& rhs) const { return c < rhs.c; }
};
Here's my test code. Notice how the first two lines return the same pointer, so these semantics are different from normal allocation via new or make_shared.
void test_shape() {
auto s0 = make_shape(Circle{});
auto s1 = make_shape(Circle{});
// Structurally equivalent values yield the same pointer.
assert(s0 == s1);
// Color is red by default, so we should get the same pointer.
auto s2 = s0->color(Red);
assert(s2 == s0);
// Changing to Green gives us a different pointer.
auto s3 = s0->color(Green);
assert(s3 != s0);
printf("done\n");
}
int main() {
test_shape();
}
Right now, the shapes are simply leaked. That is to say that once a client of this data model no longer has a pointer to a Shape, that shape is not deallocated (consider the set to be weak references that should be broken).
So I'd like to use shared_ptr to manage my objects, because it seems simple (also open to other ideas, but I don't want to add dependencies, like boost).
But I'm having a little trouble with shared_ptr. I've tried updating the std::set to store std::weak_ptr<const T> with a comparison using owner_before.
I need a shared_ptr to look up the object in the set. But that would require newing an object, and part of the point here is to be able to quickly get an existing structurally equal object.
Update
I also tried keeping the set as raw pointers, and using the shared_ptr deleter to remove elements. Alas, that requires me to use shared_from_this which seems to balk, though I'm not exactly sure why:
shape.cpp:30:16: error: member reference base type 'Circle *const' is not a
structure or union
return iter->shared_from_this();
~~~~^ ~~~~~~~~~~~~~~~~
One alternative solution is for your clients to use a factory that owns the objects it hands out. This way your clients can use plain pointers to refer to objects.
Once the client is done, it can dispose of the factory along with all the objects.
In addition, may be, have the factory reference counted, or keep a shared_ptr to it.
Here's the complete code. Turns out I'm just not very good at programming and didn't realize I had to deref something.
Basic approach is that the shared_ptr deleter removes the raw pointer from the set.
#include <set>
#include <cassert>
#include <memory>
enum Color { Red, Green, Blue };
struct Shape;
struct Circle;
struct Shape : public std::enable_shared_from_this<Shape> {
virtual ~Shape() = default;
// Set the color, return a new shape.
virtual std::shared_ptr<Shape> color(Color) const = 0;
};
template<class T>
std::shared_ptr<Shape> make_shape(T value) {
struct cmp {
bool operator()(const T* a, const T* b) const {
return *a < *b;
}
};
static std::set<T*, cmp> values;
auto iter = values.find(&value);
if(iter != values.end()) {
return (*iter)->shared_from_this();
}
auto ptr = std::shared_ptr<T>(new T(value), [](T* p) {
printf("deleting %p\n", (void*)p);
values.erase(p); delete p;
});
values.insert(ptr.get());
return ptr;
}
struct CircleCount {
static int count;
CircleCount() { ++count; }
CircleCount(const CircleCount&) { ++count; }
~CircleCount() { --count; }
};
int CircleCount::count;
struct Circle : public Shape {
CircleCount count;
Color c = Red;
virtual std::shared_ptr<Shape> color(Color c) const {
Circle r;
r.c = c;
return make_shape(r);
}
bool operator<(const Circle& rhs) const { return c < rhs.c; }
};
void test_shape() {
{
auto s0 = make_shape(Circle{});
auto s1 = make_shape(Circle{});
assert(s0 == s1);
auto s2 = s0->color(Red);
assert(s2 == s0);
auto s3 = s0->color(Green);
assert(s3 != s0);
}
// All circles should be cleaned up.
printf("circles: %d\n", CircleCount::count);
assert(CircleCount::count == 0);
printf("done\n");
}
int main() {
test_shape();
}
Update
I made this into something generic, which is up for code review here
I have a vector of class objects sorted by its integer indices. But the index of an object is generated by the member function of the class - so no int id is stored as a member variable.
class boundary
{
public:
int get_id();
}
std::vector<boundary> sample;
Now I need to find the boundary object ,which's int id generated by get_id() is same as the int value I'm searching.
auto &iter = binary_search(sample.begin(),sample.end(), 5, custom_function)
//should compare iter.get_id() == 5
Is it possible to use binary_search in this case? How do I achieve this?
You should use std::lower_bound in this case:
bool custom_function(boundary& obj, int id) { return obj.get_id() < id; }
...
auto iter = lower_bound(sample.begin(),sample.end(), 5, custom_function);
(replace function pointer with function object if you want better performance)
Assumption: you want to obtain a reference to the sought element (rather than an iterator to it).
boundary& find_boundary(std::vector<boundary>& sample, int id)
// precondition: a boundary with id does exist in the sample
{
auto less_by_id = [](boundary const& b, int id) // lambda is faster than function pointers
{ return b.get_id() < id; };
auto it = lower_bound(sample.begin(), sample.end(), id, less_by_id);
assert (it != sample.end());
assert (it->get_id() == id);
return *it;
}
Now, you can use it:
boundary& b = find_boundary(sample, 5);
You can create an object which satisfies the "Compare" concept.
http://en.cppreference.com/w/cpp/concept/Compare
For example:
class Compare {
public:
bool operator()(boundry a, boundry b) {
return a.get_id() < b.get_id();
}
}
Imagine the following scenario:
class A
{
int a[50];
int* GetAPtr() { return a; };
};
...
A b;
if(b.GetAPtr()[22] == SOME_RANDOM_DEFINE) do_this_and_that();
Is this kind of access considered bad practice? b.GetAPtr()[22]
To clarify my situation:
1. I cannot use new/malloc in this case, the array muste be static
2. This is meant to encapsulate older C code that uses multiple arrays where this comes extremly handy
3. I know that returning a pointer can possibly return a NULL pointer, we do not talk about that issue here
If you really need such const expression you could make it into a function:
class A
{
int a[50];
bool check_this_and_that() { return a[22] == SOME_RANDOM_DEFINE; };
};
...
A b;
if(b.check_this_and_that()) do_this_and_that();
magic numbers are bad in general but inside a class logic it's more forgiveable and outsiders don't have to see this.
Yes, it is bad practice, because you have no way of knowing how long the array is. You could follow the idiomatic standard library approach and return begin and end pointers, pointing to the first and one-past-last elements.
class A
{
int a[50];
int* begin() { return &a[0]; };
int* end() { return &a[50]; };
const int* begin() const { return &a[0]; };
const int* end() const { return &a[50]; };
size_t size() const { return 50; } // this could be handy too
};
As well as giving you the tools to iterate over the elements like you would over a standard library container, this allows you to check whether any pointer to an element of the array is < v.end(). For example
it* it = b.begin() + 22;
if(it < b.end() && *it == SOME_RANDOM_DEFINE) do_this_and_that();
This makes it trivial to use standard library algorithms:
A b;
// fill with increasing numbers
std::iota(b.begin(), b.end());
// sort in descending order
std::sort(s.begin(), s.end(), std::greater<int>());
// C++11 range based for loop
for (auto i : b)
std::cout << i << " ";
std::endl;
GetAPtr is a method for accessing a private data member. Now ask yourself what are the advantages of b.GetAPtr()[22] over b.a[22]?
Encapsulating data is a good way to maintain constraints on and between data members. In your case there is at least a correlation between the a array and its length 50.
Depending on the use of A you could build a interface providing different access patterns:
class A {
int a[50];
public:
// low level
int atA(unsigned i) const { return a[i]; }
// or "mid" level
int getA(unsigned i) const { if(i >= 50) throw OutOfRange(); return a[i]; };
// or high level
bool checkSomething() const { return a[22] == SOME_RANDOM_DEFINE; }
};
Trying to make a simple card game program. I'm having trouble with the vector::erase(); function on a vector made of of type Card. It seems that it can't use it because there isn't an overloaded function in vector::erase(); that deals with a <Card>. This confuses me because a vector is templated.
#include <iostream>
#include <vector>
#include <algorithm>
enum card_suit {SPADE, CLUB, DIAMOND, HEART};
class Card;
class Player;
class Deck;
class Card
{
unsigned short rank;
card_suit suit;
public:
Card(unsigned short r, card_suit s)
{
rank = r;
suit = s;
}
bool operator == (Card& a)
{
if(this->rank == a.rank && this->suit == a.suit) return true;
else return false;
}
};
class Deck
{
std::vector<Card> cards;
public:
Deck& add_card(Card c)
{
cards.push_back(c);
return *this;
}
Deck& remove_card(Card c)
{
for(std::vector<Card>::iterator i=cards.begin(); i<cards.end(); i++)
{
if(*i==c) cards.erase(cards.begin()-i);
}
return *this;
}
Deck& shuffle()
{
}
};
class Player
{
Deck hand;
unsigned short points;
public:
Player()
{
points=0;
}
};
int main()
{
return 0;
}
Any idea what to do?
This should generally work, provided you get the basic syntax and idioms right:
for (std::vector<Card>::iterator it = cards.begin(), end = cards.end(); it != end; ++it)
{
if (c == *it)
{
cards.erase(it);
break;
}
}
Note that erasing from the container invalidates iterators, so we can only erase one element. We can't use the usual erase(it++) here, because all iterators beyond the erased one are invalidated by the erase.
In order to efficiently remove all matching elements from a vector, and you should instead use the remove+erase idiom:
cards.erase(std::remove(cards.begin(), cards.end(), c), cards.end());
This first reorders the elements of the vector so that all those that match c are at the end (remove), and then (efficiently) erases that end from the vector (erase).
If you want to remove just one card, then instead of this
if(*i==c) cards.erase(cards.begin()-i);
do this:
if(*i==c) cards.erase(i);
If I do not miss something you just need to replace cards.erase(cards.begin()-i); with cards.erase(i);. Really I cannot understand what do you mean by that code.
Well, if to speak about effectiveness I guess that the card order makes no sense and we can use this feature:
std::vector<Card>::iterator i = std::find( cards.begin(), cards.end(), c );
if ( i != cards.end() ) {
if ( i != (cards.end()-1) )
*i = *(cards.end()-1);
cards.pop_back();
}
*The suggested erase-remove combination results in copies of the vector tail.
The problem is:
cards.begin() - i
// ^^^^
The result of this expression is an ptr_diff.
While the erase() method takes an iterator.
Maybe you meant:
cards.erase( i );