dynamic cast from array in c++ - c++

I have a class STSequencer which extends ofxDTanbileBase.
I have a method which returns a vector<ofxDTanbileBase> based on the className i give.
I want to cast back to STSequencer but i get the following errors:
'ofxDTangibleBase *' is not a class
Dynamic_cast from rvalue to reference type 'STSequencer &'
This is how i try atm:
vector<ofxDTangibleBase> sequencers = gTangibleList->findTangibleByClassName("STSequencer");
for (int i = 0; i < sequencers.size(); i++) {
STSequencer &sequencer = dynamic_cast<STSequencer&>(&sequencers[i]);
}
This is the method:
vector<ofxDTangibleBase> ofxDGlobalTangibleList::findTangibleByClassName(const char *className) {
vector<ofxDTangibleBase> returnVector;
for (int i = 0; i < _tangibles.size(); i++) {
ofxDTangibleBase &t = _tangibles[i];
if (t.className == className) {
returnVector.push_back(t);
}
}
return returnVector;
}
A better way is also welcome.

STSequencer &sequencer = dynamic_cast<STSequencer&>
should be
STSequencer *sequencer = dynamic_cast<STSequencer*>
or else remove the & in front of sequencers[i]. By taking the address of sequencers[i], you have a pointer. But you are then trying to dynamic_cast to a reference, and that's not meaningful.
There are other risks if your design. You might end up copying (and slicing) elements when you don't expect it. I'm not sure what you're doing. For this answer, I just looked at the line that failed to compile.

Your vector does not actually contain STSequencer objects, so that cast will lead to undefined behavior, even after you fix the levels of indirection (reference vs pointer) problem.
If you really need polymorphism, you'll need to store addresses in the vector, not objects, because the vector makes assumptions about the size of its elements.
Try std::vector<std::unique_ptr<ofxDTanbileBase>>.

Related

Iterator throwing an error when converting to string*

Consider the following piece of code, where: list<string> elements
bool SearchElement(const string& product) {
for (list<string>::iterator it = elements.begin(); it != elements.end();i++) {
string& element = *it;
if ( element == product) {
return true;
}
}
return false;
}
I want to rewrite it using a pointer:
bool SearchElement(const string& product) {
for (list<string>::iterator it = elements.begin(); it != elements.end();i++) {
string* pelement = it;
if ( *pelement == product) {
return true;
}
}
return false;
}
But it is throwing an error:
C:\Users...\C++\IShoppingApp.h:141: error: cannot convert
'std::__cxx11::liststd::__cxx11::basic_string<char >::iterator' {aka
'std::_List_iteratorstd::__cxx11::basic_string<char >'} to
'std::__cxx11::string*' {aka 'std::__cxx11::basic_string*'} in
initialization In file included from C:/Users/....
My professor said an iterator is roughly speaking a pointer, so I expected to use it as such. Why am I getting this error and how do I fix it?
An iterator acts like a pointer, but it is not a pointer. It refers to a value, but it is not itself a pointer. You can get a pointer, though:
string* pelement = &*it;
Note that although & and * are inverse operations on regular pointers, they are not so in general, and many types (specifically, iterators) override * to behave differently, so the two do not cancel out. It's also possible to override &, although there are fewer justifiable use cases that I can think of for that.
Based on the comments, I think you already understand this, but you want a reference. Raw pointers are generally frowned upon in modern C++, and a reference clearly conveys your intent of "I'm borrowing this for a second, I might modify it, but I'm not responsible for deleting it". Getting it to a pointer for educational purposes is fine, but the reference approach is the correct C++ way to do what you're doing.

How to dynamically created objects and access their pointer

This might seem like a trivial issue, but I can't seem to find a solution.
What I have:
void VideoHandler::demoBurn(QString fileName) {
// Create a reader for a video
openshot::FFmpegReader r("raw_videos/example0.mp4");
r.Open(); // Open the target reader
// Create a writer
openshot::FFmpegWriter w("edited_videos/NewVideo.mp4");
w.SetAudioOptions(true, "libvorbis", 44100, 2, openshot::ChannelLayout::LAYOUT_STEREO, 128000);
w.SetVideoOptions(true,"libx264" , openshot::Fraction(30,1), r.info.width, r.info.height, openshot::Fraction(1,1), false, false, 300000);
w.Open();
openshot::Timeline t(r.info.width,r.info.height, r.info.fps, 44100,2, openshot::ChannelLayout::LAYOUT_STEREO);
// Clip example
openshot::Clip c1(new openshot::QtImageReader("edited_videos/0.png"));
c1.Layer(1);
c1.Position(5.9);
c1.Start(5.9);
c1.End(10.0);
c1.scale = openshot::SCALE_NONE;
c1.gravity = openshot::GRAVITY_TOP_LEFT;
c1.location_x = 0.0;
c1.location_y = 0.2;
std::list<openshot::Clip> clipList;
for (int i = 0; i < 2; i++) {
QString imageName = QString("edited_videos/%1.png").arg(i);
clipList.push_back(openshot::Clip(new openshot::QtImageReader(imageName.toUtf8().toStdString())));
}
// Add clip values and add to timeline
std::list<openshot::Clip>::iterator it;
int test = 0;
for (it = clipList.begin(); it != clipList.end(); it++) {
it->Layer(1);
if(test == 0) {
it->Position(5.9);
it->Start(5.9);
it->End(10.0);
} else {
it->Position(10.0);
it->Start(10.0);
it->End(15.0);
}
it->scale = openshot::SCALE_NONE;
it->gravity = openshot::GRAVITY_TOP_LEFT;
it->location_x = 0.0;
it->location_y = 0.2;
test++;
t.AddClip(&it);
}
// Add clips to timeline
t.AddClip(&c1);
openshot::Clip c2(new openshot::FFmpegReader("raw_videos/example0.mp4"));
c2.Position(0.0);
c2.Layer(0);
t.AddClip(&c2);
// Open the timeline reader
t.Open();
// Close the timeline reader
w.WriteFrame(&t, 1, r.info.video_length);
// Close the reader & writer
t.Close();
w.Close();
r.Close();
}
I'm using libopenshot to burn some image overlays to the video, and since I don't know how many images there will be, I need to dynamically create a openshot::Clip for each one and give it some values.
I saw some examples on dynamic object allocation and thought this should work, but I'm getting compile errors:
/usr/include/c++/7/ext/new_allocator.h:136: error: use of deleted function ‘openshot::Clip::Clip(const openshot::Clip&)’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
/home/3rdparty/libopenshot/include/Clip.h:95: error: ‘juce::CriticalSection::CriticalSection(const juce::CriticalSection&)’ is private within this context
And for t.AddClip(&it) error:
cannot initialize a parameter of type 'openshot::Clip *' with an rvalue of type 'std::list<openshot::Clip>::iterator *' (aka '_List_iterator<openshot::Clip> *')
I can somewhat understand this error, but how do I give it the right pointer, I thought the it would hold the pointer to the object?
Since I never done dynamic object allocation, I'm not sure if this is the right way of doing it, am I using a wrong type of list?
std::list<openshot::Clip>::iterator it;
...
t.AddClip(&it);
I thought the it would hold the pointer to the object?
When you use the addressof operator - i.e. the unary & operator - on a value, what you get is pointer to that object. In this case, you use &it, and therefore you get a pointer to it. it is an iterator to a list.
However, AddClip is not expecting a pointer to an iterator. It is expecting a pointer to a openshot::Clip object. That is why you get the error:
cannot initialize a parameter of type [pointer to clip] with an rvalue of type [pointer to iterator]
I don't see how this could be affected by what the iterator "holds".
How might you get a pointer to a clip object? You apply the addressof operator on such object - rather than applying addressof operator on an object of some other type such as an iterator.
How might you get a clip object? You have an iterator to such object; you can indirect through the iterator to get the object.
How might you indirect through an iterator? You use the indirection operator i.e. the unary * operator.
For example:
t.AddClip(&*it);
Since I never done dynamic object allocation, I'm not sure if this is the right way of doing it
I don't know of openshot, so I cannot be certain, but those bare new expressions seem dubious. Unless that API mandates it, you should probably be using a unique pointer assuming dynamic allocation is needed in the first place.
After many trial and error, I managed to get it to work. What I changed is:
created a list of pointers (doesn't matter if it's QList or std:list, tested and both work the same)
and re-referenced all the iteration objects with pointers to the actual object.
Thanks to #eerorika for the info about (&*it)
QList<openshot::Clip*> clipList;
for (int i = 0; i < 2; i++) {
QString imageName = QString("edited_videos/%1.png").arg(i);
clipList.push_back(new openshot::Clip(new openshot::QtImageReader(imageName.toUtf8().toStdString())));
}
// Add clip values and add to timeline
QList<openshot::Clip*>::iterator it;
int test = 0;
for (it = clipList.begin(); it != clipList.end(); it++) {
(*it)->Layer(1);
if(test == 0) {
(*it)->Position(5.9);
(*it)->Start(5.9);
(*it)->End(10.0);
} else {
(*it)->Position(10.0);
(*it)->Start(10.0);
(*it)->End(15.0);
}
(*it)->scale = openshot::SCALE_NONE;
(*it)->gravity = openshot::GRAVITY_TOP_LEFT;
(*it)->location_x = 0.0;
(*it)->location_y = 0.2;
test++;
t.AddClip(&*(*it));
}

Shared pointer (this)

I have got an exception throw :0x74AC4192 in main.exe: Microsoft C++ exception: std::bad_weak_ptr at memory location 0x001AF0D0.
in
Gasstation::Gasstation(int n,int m)
{
for (int i = 0; i < n; ++i)
{
pumps_.push_back(std::make_shared<Pumplace>());
}
cashregisters_ = std::make_shared<Cashregister> (shared_from_this(), m);
}
I also used this in the header :
class Gasstation : public std::enable_shared_from_this<Gasstation>
What could be the problem?
The issue with your code here, is that you are calling shared_from_this() within the constructor of the class itself, where strictly speaking, it has not been "made shared" yet. The constructor is called before a smart pointer to the object exists. To follow your example, if creating a shared_ptr to Gasstation:
std::shared_ptr<Gasstation> gasStation = std::make_shared<Gasstation>(5,10);
//gasStation is available as a smart pointer, only from this point forward
Its a limitation of enable_shared_from_this that shared_from_this cannot be called in a constructor.
One solution, though not as elegant, is to have a public method that sets the cashregisters_ variable. The method can be called after construction:
Gasstation::Gasstation(int n, int m)
{
for (int i = 0; i < n; ++i)
{
pumps_.push_back(std::make_shared<Pumplace>());
}
cashregisters_ = std::make_shared<Cashregsiter>(m);
}
Gasstation::initialise_cashregisters()
{
cashregisters_->set_gasstation(shared_from_this());
}
//driver code
std::shared_ptr<Gasstation> gasStation = std::make_shared<Gasstation>(5, 10);
gasStation->initialise_cashregisters();
This solution will require you to remember to call initialise_cashregisters every time you initialise Gasstation.
Short of that, your options are limited, and you may have to rethink your design. Have you considered using raw pointers-to-Gasstation in Cashregister instead of smart pointers? If cashregister_ is a private variable and will never exist beyond the lifetime of the Gasstation it is assigned to, using raw pointers may be a safe and elegant alternative.

C++ - passing smart pointer derived class

I have a class Character that inherits from a base class CollidableObject. CollidableObject has, as you may have guessed, methods to detect collisions between other CollidableObjects, such as CircleCollidableObject and SquareCollidableObject.
bool CollidableObject::collidesWith(std::shared_ptr<CollidableObject> &pCollidable)
{
...
}
I use this to run other checks, and eventually handle the collision. Basically I want to be able to loop through the characters in my game, pass in two Characters (that, again, inherit from CollidableObject), and detect any collisions.
void CharacterManager::collisions()
{
for(std::vector<std::shared_ptr<Character>>::iterator i = mCharacters_.begin(); i != mCharacters_.end(); i++) {
for(std::vector<std::shared_ptr<Character>>::iterator j = mCharacters_.begin(); j != mCharacters_.end(); j++) {
if(i == j) continue;
(*i)->collidesWith(*j);
...
}
I'd rather not make the mCharacters_ vector into a vector of CollidableObjects if I dont have to. But I'm not sure if that's the only way.
Can you rewrite the interface? There's nothing wrong with having:
bool CollidableObject::collidesWith(const CollidableObject* pCollidable)
Presumably collidesWith isn't going to take ownership of the pointer you pass in, so passing in a raw pointer is fine.
That said, shared_ptr<CollidableObject> is actually constructible from shared_ptr<Character>. So if you want to take a shared_ptr, you'll have to take it by const reference instead of by reference. That is:
bool CollidableObject::collidesWith(const std::shared_ptr<CollidableObject>& p)
or just by-value:
bool CollidableObject::collidesWith(std::shared_ptr<CollidableObject> p)
See constructor #9 from this reference.
And if you're using std::shared_ptr, you should at least use auto in your loops to reduce the verbosity. And the j loop can start one-past i to avoid double-checking every pair:
for (auto i = mCharacters_.begin(); i != mCharacters_.end(); ++i) {
for (auto j = std::next(i); j != mCharacters_.end(); ++j) {
(*i)->collidesWith(j->get());
...
}
}

What would I return in this situation

I will post my code then explain my query:
typedef std::shared_ptr<SEntity> Entity;
//Scene_Ids is an enum
static std::map<Scene_Ids, std::vector<Entity> > m_scene_entities;
std::shared_ptr<SEntity>& SEntityManager::getEntity(const std::string& entity_name)
{
int counter = 0;
for (auto iter = m_scene_entities.begin(); iter != m_scene_entities.end(); ++iter)
{
if (iter->second[counter]->getId() == entity_name)
return iter->second[counter];
counter++;
}
//What would I return if the entity couldn't be found?
}
The code basically explains it all. I have a method in which if an "entity" is found in the std::vector inside of the map, it will return a reference to the std::shared_ptr type that it is. However, since I'm not returning a pointer, I cannot return nullptr. What could I return in a failure case.
Also, I know that std::shared_ptr is meant for having copies in several different places. For this, do I really need to return a reference or can I just return it by value?
Thanks!
Return the iterator rather than the contents of the iterator. That way you can tell whether you reached the end.
If it is expected that under normal circumstances getEntity will never fail to find the entity, then you should throw an exception.
If you would expect to fail to find some entites, then you can return a default-constructed shared_ptr <SEntity>. Be sure to check for that on the other end.
Remove the return by reference then return an empty shared pointer:
std::shared_ptr<SEntity> SEntityManager::getEntity(const std::string& entity_name) {
for { ... }
return Entity();
}
There's not really a good reason to return the shared pointer by reference. And the shared pointer has a default constructor that's basically the equivalent of nullptr. You can check it in the parent function by testing it as a bool. E.g.:
auto val = getEntity(...);
if (!val) { /* nothing found */ }
I suspect that you need to split tasks. For any normal operation (changing the values of SEntity parameters) you will just need to either return default constructed std::shared_ptr or found entity. No reference needed.
For *replacing the actual contents of shared_ptr* you can have a function like
void SEntityManager::replaceEntity(const std::string& entity_name, Entity* newEntity)
and replace the Entity if its found inside the function.
However, your code still is weird - what if, for example, there are multiple entity_name containing Entities in your vectors ?