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")
Related
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));
}
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.
I want to be able to pass a struct member into a function:
struct threeBuckets {
int bucketA;
int bucketB;
int bucketC;
};
threeBuckets allCombinations[512000] = {{0,0,0}};
int totalCombinations = 1;
int counter = 0;
//note that pourer, receiver, and other are one of the struct members (bucketA, bucketB, and bucketC)
void pour(pourer, receiver, int receiverCap, other) {
int finalTriple[3];
allCombinations[totalCombinations].bucketA = allCombinations[counter].bucketA;
allCombinations[totalCombinations].bucketB = allCombinations[counter].bucketB;
allCombinations[totalCombinations].bucketC = allCombinations[counter].bucketC;
allCombinations[totalCombinations].receiver = allCombinations[totalCombinations].receiver + allCombinations[counter].pourer;
allCombinations[totalCombinations].pourer = 0;
if (allCombinations[totalCombinations].receiver > receiverCap) {
allCombinations[totalCombinations].pourer = allCombinations[totalCombinations].pourer + allCombinations[totalCombinations].receiver - receiverCap;
allCombinations[totalCombinations].receiver = receiverCap;
}
finalTriple[0] = allCombinations[totalCombinations].bucketA;
finalTriple[1] = allCombinations[totalCombinations].bucketB;
finalTriple[2] = allCombinations[totalCombinations].bucketC;
//some more irrelevant code
}
As I've hopefully made clear, the parameters pourer, receiver, and other are bucketA, bucketB, and bucketC (in no particular order, the order does change depending on when I call the function.) There are several places where I want to modify the instance
allCombinations[totalCombinations].pourer
for example. How do I use the struct member as a parameter, and what type do I use to specify it?
Note: I'm mostly a beginner and am new to StackOverflow, so if anything else I'm doing is wrong, please feel free to tell me.
Note 2: If any of you do or have done USACO, you might recognize this problem as the milk3 training gateway problem. This might aid you if you don't know what I'm doing here.
It sounds like you need to use pointer to member variable for the argument types in pour.
void pour(double threeBuckets::(*pourer) ,
double threeBuckets::(*receiver),
int receiverCap,
double threeBuckets::(*other)) {
...
}
In the function, change the use of
allCombinations[totalCombinations].pourer
allCombinations[totalCombinations].receiver
allCombinations[totalCombinations].other
by
allCombinations[totalCombinations].*pourer
allCombinations[totalCombinations].*receiver
allCombinations[totalCombinations].*other
respectively.
At the point of calling the function, use:
pour(&threeBuckets::bucketA,
&threeBuckets::bucketB,
0, // Any appropriate value
&threeBuckets::bucketC);
Another option that is worth considering is:
Change threeBuckets to use an array.
Change the arguments to pour to be indices to the array.
struct threeBuckets {
int buckets[3];
};
void pour(int pourerIndex ,
int receiverIndex,
int receiverCap,
int otherIndex)) {
...
}
Then, instead of using
allCombinations[totalCombinations].pourer
allCombinations[totalCombinations].receiver
allCombinations[totalCombinations].other
use
allCombinations[totalCombinations].buckets[pourerIndex]
allCombinations[totalCombinations].buckets[receiverIndex]
allCombinations[totalCombinations].buckets[otherIndex]
Of course, change the call to use indices.
pour(0,
1
0, // Any appropriate value
2);
I am currently working on an dynamic memory container.
Basic idea of the class is that you should be able to get the iterator of an object if you really do not know it, without the use of a for loop throughout all the elements to boost performance. The issue I have is the following; when you pass your pointer address to the object you want to get the iterator of it type casts the object into the extended memory containers structures type. This type contains an extra element, an integer. (IteratorNum)
When following the code the integer within the function is set to correct value, as below would be 50. But when the returned value is set into the local integer used in the main function it is 200? I've been adding watches and cannot figure out how it is possible that the function returns 50 but value gets set to 200.
template <typename DataType> class MemoryContainer {
public:
struct LevelData : DataType
{
int element;
};
DataType &New()
{
elements++;
//Reallocate the size of the array
ld = (LevelData*)realloc(ld, sizeof(LevelData) * elements);
//Set the iteratorNumber
ld[elements - 1].element = elements - 1;
return ld[elements - 1];
}
DataType *reserve(int num)
{
return calloc(num, sizeof(DataType));
}
DataType &operator[](int i)
{
return ld[i];
}
bool inArray(DataType *type)
{
//Compare memory addresses and see if it's within.
return (type >= &ld[0]) && (type < &ld[elements - 1]);
}
static unsigned int getIterator(DataType *type)
{
// v this is 50, but in main says returns 200.
return ((LevelData*)type)->element;
}
MemoryContainer()
{
elements = 0;
}
~MemoryContainer()
{
free(data);
}
private:
unsigned int elements;
LevelData *ld;
};
struct Effective
{
//Set it to polymorphic classes
virtual void dummy()
{
}
char * testvar;
Effective(char * c)
{
testvar = c;
}
Effective(){}
};
MemoryContainer<Effective> myContainer;
int _tmain(int argc, _TCHAR* argv[])
{
//Create 200 elements in the array
for(int i = 0; i < 200; i++)
myContainer.New().testvar = "E";
//Add pointer for testing purposes to get the iterator.
Effective * pointer = &myContainer[50];
//Test setting it's value
pointer->testvar = "HEHEHE";
//Get iterator of our pointer in the array
unsigned int i = myContainer.getIterator(pointer);
printf(pointer->testvar);
system("PAUSE");
return 0;
}
I suspect it is the visual studio debugger getting confused between your two i variables. If you print out the value of i, it will print correctly. If you change the name of your variable to something else, the value shows as 50 in the debugger.
That said, your code is a mish-mash of c and c++ and won't work correctly with anything that requires a copy constructor. I would suggest at the very least using new [] rather than realloc.
Also, any user of this collection who tries to store a class with a member variable called element is going to get mighty confused.
The unsigned int i in the main function really has a value of 50, but the debugger is confusing it with the i declared in the for loop (I reproduced this with Visual Studio 2013). If you cout i it will be 50, and if you change the variable name it will show up as 50 in the debugger. I've never seen this problem before so I wonder if it might be due to your use of malloc/realloc/free with C++ objects.
I've got a program where I have a std::vector as a member of a class:
class Blackboard
{
public:
inline std::vector<Vector2<int> > GetPath()
{ return m_path; }
inline void SetPath(std::vector<Vector2<int> > path)
{ m_path = path; }
inline void ClearPath()
{ if(m_path.size() > 0) m_path.clear(); }
private:
std::vector<Vector2<int>> m_path;
};
Where the Vector2 class is defined as:
template <class T>
class Vector2
{
private:
T m_x;
T m_y;
public:
Vector2(void)
{ m_x = 0; m_y = 0;}
Vector2(T x, T y)
{ m_x = x; m_y = y;}
~Vector2(void)
{ }
inline T x() const
{ return m_x; }
inline T y() const
{ return m_y; }
// ...
};
And at some point I call:
m_blackboard.ClearPath();
This works fine in debug, but crashes in release with the "Microsoft Visual Studio C Runtime Library has detected a fatal error in Test2.exe." message.
The call stack, at the last point where I can still see shows that:
Test2.exe!std::vector<RBT::Vector2<int>,
std::allocator<RBT::Vector2<int> > >::erase
(std::_Vector_const_iterator<RBT::Vector2<int>,
std::allocator<RBT::Vector2<int> > >
_First_arg={m_x=15 m_y=7 },
std::_Vector_const_iterator<RBT::Vector2<int>,
std::allocator<RBT::Vector2<int> > >
_Last_arg={m_x=15 m_y=8 }) Line 1037 + 0xe bytes C++
Here is where I'm calling the code that ends up crashing:
BTNode::Status GoToDestBehavior::Update()
{
BTEntityData::Node* node = m_dataRef->m_bTree.GetNode(m_index);
if(node->m_state == BTNode::STATE_READY)
{
BehaviorTree::RequestDeferredAction(Batch::PATHFIND, m_dataRef->m_entityID);
return BTNode::STATE_RUNNING;
}
else if(node->m_state == BTNode::STATE_RUNNING)
{
std::vector<Vector2<int>> path = m_dataRef->m_blackboard.GetPath();
EntitySystem::Entity* entity = EntitySystem::GetEntity(m_dataRef->m_entityID);
Assert(entity != NULL, "Invalid entity\n");
Assert(entity->HasComponent(Component::PHYSICS_COMP), "Associated entity must have physics component to move\n");
int phyIndex = entity->GetComponentIndex(Component::PHYSICS_COMP);
PhysicsSystem::PhysicsData * physicsData = PhysicsSystem::GetComponent(phyIndex);
Assert(physicsData != NULL, "Invalid physics data\n");
// Path is empty, so finish
if(path.size() == 0)
{
physicsData->m_dir = Direction::NONE; // Stop because we are here
return BTNode::STATE_SUCCESS;
}
// Remove last element if we are at it
//LogFmt("Size of vector %d\n", path.size());
Vector2<int> last = path.back();
if(last.x() == physicsData->m_posX && last.y() == physicsData->m_posY)
{
path.pop_back();
}
// Last node of the path has been transversed
if(path.size() == 0)
{
physicsData->m_dir = Direction::NONE; // Stop because we are here
m_dataRef->m_blackboard.ClearPath();
return BTNode::STATE_SUCCESS;
}
Vector2<int> step = path.back();
physicsData->m_dir = Direction::VectorToDirection(physicsData->m_posX, physicsData->m_posY, step.x(), step.y());
if(physicsData->m_dir == Direction::NONE)
{
m_dataRef->m_blackboard.SetPath(path);
return BTNode::STATE_FAIL;
}
m_dataRef->m_blackboard.SetPath(path);
return BTNode::STATE_RUNNING;
}
return BTNode::STATE_ERROR;
}
I don't know why it's behaving like this. Most similar issues I've found online have the problem of calling clear on an empty array, but I have a guard against that, so it shouldn't be the issue.
The other thing I can think of is my Vector2 class requiring some kind of copy constructor or something for when I add elements to the vector, but in the end it's just 2 ints, so I don't know why that might be failing.
I've been over this code too much and might be missing something obvious.
It's perfectly fine to call clear on an empty container of any sort.
Using my psychic debugging skills, I have determined that in code you aren't showing us you're accessing elements of the vector that don't actually exist (possibly before you inserted them, and probably with operator[]). Usually element creation is done through resize, push_back, or insert.
The other possibility is that you have another memory corruption somewhere in your program.
I found an issue I had due to a change in data format. The std::list I was using changed from a pointer to a list to directly the list. This started causing all sorts of errors that checking for the size of the list did not solve and were caused by a ZeroMemory()/memset() call that wiped out all of the tracking data of the list, since it was now part of the class instead of a pointer to the list.
If you have an empty list and call .clear() on it with a crash, chances are you have messed up the internal tracking memory as mentioned by Mark in his answer. Look for a place where you are doing memory clearing on containing classes and the like as the most likely culprits.
I know it's been 8 years, but I thought too I had this problem when I was destroying an empty bst into which my code was sending a nullptr value to the __p variable in the implementation of "new_allocator.h". This __p is needed to never be null, as mentioned in the file itself!
// __p is not permitted to be a null pointer.
The solution is not sending anything if you don't have something to send, basically.