How to dynamically created objects and access their pointer - c++

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));
}

Related

c++ "error:passing 'const std::vector<int>' as 'this' argument discards qualifiers [-fpermissive]"

I am trying to implement this POMDP solver with given examples for my decision making problem and I followed the documentation in the repository to build different relevant classes and functions in the header file
class SimpleState: public State {
public:
int position;
int context;
int time;
SimpleState();
SimpleState(int _position, int _context, int _time) :
rat_position(_position),
context(_context),
time(_time) {
}
SimpleState(int _state_id);
~SimpleState();
std::string text() const;
};
SimpleState::SimpleState() {
}
class StarMazeProblem : public DSPOMDP,
public MDP {
protected:
std::vector<std::vector<std::vector<State> > > transition_probabilities_; //state, action, [state, weight]
mutable MemoryPool<SimpleState> memory_pool_;
std::vector<SimpleState*> states_;
mutable std::vector<ValuedAction> mdp_policy_;
public:
enum {CENTER = 0, RIGHT = 1, LEFT = 2};
public:
StarMazeProblem();
int NumStates() const;
void ComputeDefaultActions(std::string type) const;
ParticleUpperBound* CreateParticleUpperBound(std::string name = "DEFAULT") const;//?
ScenarioUpperBound* CreateScenarioUpperBound(std::string name = "DEFAULT",
std::string particle_bound_name = "DEFAULT") const;
ScenarioLowerBound* CreateScenarioLowerBound(std::string name = "DEFAULT",
std::string particle_bound_name = "DEFAULT") const;
}
and in the starmaze.cpp file the relevant lines are
int StarMazeProblem::NumStates() const {
return CONTEXT * POSITIONS * TIME;
}
void StarMazeProblem::ComputeDefaultActions(string type) const {
cerr << "Default action = " << type << endl;
if (type == "MDP") {
const_cast<StarMazeProblem*>(this)->ComputeOptimalPolicyUsingVI();
int num_states = NumStates();
default_action_.resize(num_states);
double value = 0;
for (int s = 0; s < num_states; s++) {
default_action_[s] = policy_[s].action;
value += policy_[s].value;
}
} else {
cerr << "Unsupported default action type " << type << endl;
exit(0);
}
}
ScenarioLowerBound* StarMazeProblem::CreateScenarioLowerBound(string name,
string particle_bound_name="DEFAULT") const {
const DSPOMDP* model = this;
const StateIndexer* indexer = this;
const StatePolicy* policy = this;
ScenarioLowerBound* bound = NULL;
if (name == "TRIVIAL" ) {
bound = new TrivialParticleLowerBound(this);
} else if (name == "RANDOM") {
bound = new RandomPolicy(this,
CreateParticleLowerBound(particle_bound_name));
} else if (name == "MODE" || name == "DEFAULT") {
ComputeDefaultActions("MDP");
bound = new ModeStatePolicy(model, *indexer, *policy,
CreateParticleLowerBound(particle_bound_name));
} else {
cerr << "Unsupported scenario lower bound: " << name << endl;
exit(1);
}
return bound;
}
here I got the following error for the above code:
src/starmaze.cpp:301:36: error: passing 'const std::vector<int>' as 'this' argument discards qualifiers [-fpermissive]
default_action_.resize(num_states);
^
In file included from /opt/local/include/gcc7/c++/vector:64:0,
from ../../../include/despot/interface/lower_bound.h:4,
from ../../../include/despot/core/builtin_lower_bounds.h:4,
from src/starmaze.h:3,
from src/starmaze.cpp:1:
/opt/local/include/gcc7/c++/bits/stl_vector.h:689:7: note: in call to 'void std::vector<_Tp, _Alloc>::resize(std::vector<_Tp, _Alloc>::size_type) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]'
resize(size_type __new_size)
^~~~~~
I have basic c++ knowledge and I could not figure out the reason for the error since I followed the examples. Any suggestion?
Important to know before reading
I've looked over this code several times, and cannot find where default_action_ is declared as a const std::vector<int>. This leads me to assume (based on the fact that the compiler recognizes it as such) that the variable is declared in one of the parent classes: public DSPOMDP, public MDP.
You are trying to modify a const vector<int>
This issue is pretty straight-forward.
You cannot change a const std::vector<Ty>
The whole point of making something const is to prevent the programmer from changing it.
Whatever you are trying to do here, you should consider copying the vector data into a new vector, and make the changes to it in the copy.
Okay so let's say you decided to do the naughty deed and remove const from the *.h file wherever it may be. You'll still have an issue (see below)
You are trying to modify the class instance from a const method
This is if you removed const from the vector
The default_action_.resize(num_states); is going to cause the compiler to yell at you.
The issue here is now your method StarMazeProblem::ComputeDefaultActions() is specified as const. This means you cannot change your class instance in any way from within that function/class method. What you are doing is modifying the default_action_ vector by calling resize() on it. This inevitably changes the class instance which is forbidden because your method is declared const and your default_action_ vector is declared somewhere in your class hierarchy. Additionally you are changing the vector directly by assigning it to an rvalue (See code below)
int num_states = NumStates();
default_action_.resize(num_states); // <---- default_action_ cannot be modified
for (int s = 0; s < num_states; s++) {
default_action_[s] = policy_[s].action; // <---- default_action_ cannot be modified
value += policy_[s].value;
}
Solution
You need a copy of the vector you are trying to modify. Going into h files and changing them without knowing 100% exactly what you are doing is never the answer.
Making a temporary vector in the class method, copying the data to it, and manipulating the copy is completely allowed and will not give you any compiler errors; however, this approach may completely avoid your official goal. It looks like you are really trying to change the default_action_ vector and that almost seems like your true goal here.
It's hard for me to give you a definitive answer on this specific topic. Mainly because I do not know what this entire class hierarchy does or what it is for exactly (I briefly looked over the code in the link provided.)
What you'll need to do ultimately is determine why you are trying to change that vector, and why it was made const by the original developers. Then you can determine if there is a better way other than explicitly removing the constness of the vector.
If you are still trying to make changes to the class instance read below
This solution part has to do with the qualifier of the class you are dealing with.
You can either remove the constant qualifier from the class method if it is absolutely necessary to make changes to the class instance from within that method.
OR
Find an alternative method for what you are trying to do, and break it up into multiple method calls on the class instance.
You've made ComputeDefaultActions() const-qualified, but there is very little that says that it should be.
It calls ComputeOptimalPolicyUsingVI() which is not const-qualified since it changes the internal state of *this. You've worked around that by casting away const on this - but that function resizes policy_ to also be NumStates() big which ComputeDefaultActions() depends on - otherwise the internal loop would be very dangerous.
It changes default_action_ by resizeing it and by assigning its elements. This may be a mistake, if the computation made is actually meant to not change *this but ... (see next bullet)
It doesn't return anything. Everything the function does is to change the internal state of *this. The computed value is just dropped at the end of the calculation and it's not even used internally in the function. Either make the function return value or remove value completely.
Suggested changes:
#include <algorithm>
#include <stdexcept>
void StarMazeProblem::ComputeDefaultActions(string type) { // non-const
cerr << "Default action = " << type << endl;
if (type == "MDP") {
ComputeOptimalPolicyUsingVI(); // no casting needed
default_action_.resize(policy_.size()); // dependency made clear
// Use the standard transform function:
std::transform(policy_.begin(), policy_.end(), default_action_.begin(),
[](const auto& p) { return p.action; });
} else {
// friendlier than exit():
throw std::runtime_error("Unsupported default action type " + type);
}
}

Looking for any way to increment ENUM type without operator overloading

so this is about an assignment.
I have a header file with predefined ENUM type (TDay) which I CANNOT change in any way. TDay does not support any operator other than streams.
My problem is I need to find a way to do something like this:
Object::Object (uint aSize) {
Object temp; // contains varible inicialized to zero, this variable can be bool, int, RGB structure
// or TDay enum. I also can't use templates here.
for (int i = 0; i < aSize; i++) {
this->array[i] = temp.Value() + 1; // array is of the same type as Value
}
}
This code is just for illustration of what I need to do, don't look for any use of this I just made it up just to better explain my problem.
So anyway this doesn't work because my TDay doesn't support TDay+int operator.
Is there any way around this? Solution doesn't have to be clean, I'll accept any pointer cheats.
EDIT:
So I tried putting in my Object.cpp file this:
TDay operator+(TDay aDay, int aValue) {
return static_cast<TDay>(int(aDay) + aValue);
}
And it doesn't work. Compiler error says:
Argument of type int is imcompatible with parameter of type TDay
However if I put this code to TDay.h it works fine. Is something wrong with my linker?
I would create a function taking current ENUM value named for example increase
void increase(your_enum& e){
if(e == e::MAX_VAL)
e = e::MIN_VAL; //if you have it, otherwise do same as below
else{
int val = int(e); //cast it to int
val++;
e = static_cast<your_enum>(val); //cast it back
}
}
Creating a function taking another parameter to increase/decrease by more than one should be easy from this point.

Proper way of casting for a method reference parameter

I have an array of objects stored. I want to reach them. The below code works just fine:
class Primitive
{
public:
int SomePrimitiveValue = 5;
};
class Derived : public Primitive
{
public:
int SomeDerivedValue = 8;
};
Primitive * ExtractTheLast()
{
if (FCount > 0)
{
Primitive * result = *((Primitive**)((char*)FData + (FCount - 1 * TypeSize())));
RemoveByIndex(FCount - 1);
return result;
}
return nullptr;
}
int main()
{
Derived * result = (Derived *)ExtractTheLast();
if (!result)
result = new Derived();
}
but I want to see if this access operation ExtractTheLast is successful so I modified the code such as;
bool ExtractTheLast(Primitive *& lastItem)
{
if (FCount > 0)
{
lastItem = *((Primitive**)((char*)FData + (FCount - 1 * TypeSize())));
RemoveByIndex(FCount - 1);
return true;
}
lastItem = nullptr;
return false;
}
int main()
{
Derived * result = nullptr;
if (!ExtractTheLast((Primitive*&)result))
result = new Derived();
}
In this code ExtractTheLast((Primitive*&)result) doesn't worked as I intended, my guess is compiler converting or maybe treating the content data of the class as it is Primitive and returns a broken object.
My question is how can I properly type cast inside a method's parameter zone? and I really don't want to use templates like ExtractTheLast<Derived>().
-------------------EDIT---------------------
After i realized my question is not clear enough, i try to summerize it but couldn't create the same result as in my project so i decided showing two way which first one works but the second one gives funny resluts.
Please bare in mind that i only want to know the difference between those two line of codes
(RenderRequestO *)Requests_idle->GetTheLast()
and
Requests_idle->GetTheLast((PrimitiveO*&)result)
one of them returns the object directly and other one returns it as parameter and i think when i try to type cast inside the parameter block, compiler gives wrong result.
this is the code works fine:
MutexLock(mutex);
RenderRequestO * result = Requests_idle->Count() > 0 ? (RenderRequestO *)Requests_idle->GetTheLast() : new RenderRequestO();
if (Requests_idle->Count() > 0)
Requests_idle->RemoveLast();
...
..
and this is the code doesn't work as i want it to be:
MutexLock(mutex);
RenderRequestO * result = nullptr;
if (!Requests_idle->GetTheLast((PrimitiveO*&)result))
result = new RenderRequestO();
...
..
if i get the related object such as (RenderRequestO *)Requests_idle->GetTheLast() it works fine but if i get try to get it like Requests_idle->GetTheLast((PrimitiveO*&)result) it returns an object but its derived fields are all inaccessable (when i move my mouse over it intellisense says "unable to read memory")

A decent way to transform a const list reference argument then pass to another function?

Sorry for not addressing problem precisely in the title, here's the thing.
Let's say I'm an adapter, and I have to redirect a function to another,
which are listing below:
My owner would call my function and pass an argument to me first like this:
void receive (const list<Obj>& Larr){
// do some transforming
// Then call "send"
}
And then I have to call someone else, but with the different container argument:
void send (const vector<Obj*>& Varr){
// ....
}
Because of the constraints of 'const', so apparently, I CANNOT just do 'push_back' pointer of the elements iteration by iteration like:
void receive (const list<Obj>& Larr){
for (list<Obj>::const_iterator it = Larr.begin(); it != Larr.end(); it++)
// vec is my class member
vec.push_back(&(*it)); // compile error: no match function
// Because expected element is (Obj*) rather than (const Obj*)
}
So the only way I think of is to COPY every element in Larr, then push_back their address in the vector, which I'm about to broadcast :
void receive (const list<Obj>& Larr){
vector<Obj> tmp(Larr.size());
int i = 0;
for (list<Obj>::const_iterator it = Larr.begin(); it != Larr.end(); it++, i++){
tmp[i] = *it;
}
for (i = 0; i < tmp.size(); i++)
vec.push_back(&tmp[i]);
// Call send here;
send(vec); // The lifecyle of tmp is ensured, no need to worry about
}
Now my question is, under this scenario, not allowing changing interface, is there any way that I can achieve this without copying every single element in the function?
You are correct about the constraints of const, by definition it cannot be modified. Your only options are to convert the list to a vector or overload your send method to support list types.
You may use the range based constructor to simplify your vector construction i.e.
std::vector<Obj> tmp{ Larr.begin(), Larr.end() };

dynamic cast from array in 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>>.