Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
I have a little complicated problem. I'll try to explain what I've done.
I have a big class, which has as class-members
Mat vidImg
vector<Mat*> *VideoBuffer;
unsigned int currentVideoFrame;
I also have a class method
void loadVideoInBuffer(int num)
{
VideoBuffer.clear();
currentVideoFrame = 0;
vidDev.open(ListVideos.at(num).absoluteFilePath().toStdString()); // open videofile
while(true)
{
if(vidDev.read(vidImg) == false) // read from file int vidImg object
break;
VideoBuffer.push_back(new Mat(vidImg)); // pushback into vector
}
ui->tbVideo->setEnabled(true);
}
In this I am loading some objects loaded from another file into the Videobuffer vector.
If I try to load it again from this vector in another class-member which I am assigning here:
void grabAndProcessFrameVideo() // reload and show loaded inage
{
if(vidFlag == true)
{
vidImg = Mat(*(VideoBuffer[currentVideoFrame])); // load from vector
currentVideoFrame++; // inc index for vector
imshow("img",vidImg); // show reloaded object in another window
}
}
The Mat Object and imshow function are from the opencv lib but I think that this doesn't really matter. My problem is, that it just shows the last image. If I try to access the buffervector directly in the loading function in this way
void EAMViewer::loadVideoInBuffer(int num)
{
ui->tbVideo->setDisabled(true);
VideoBuffer.clear();
currentVideoFrame = 0;
if(vidDev.open(ListVideos.at(num).absoluteFilePath().toStdString()) == false)
{
newLineInText(tr("no Device found"));
return;
}
while(true)
{
if(vidDev.read(vidImg) == false)
break;
VideoBuffer.push_back(new Mat(vidImg));
imshow("img",Mat(*(VideoBuffer)[currentVideoFrame]));
waitKey(30);
currentVideoFrame++;
}
currentVideoFrame = 0;
ui->tbVideo->setEnabled(true);
}
Then it shows me it as wanted. So I think that the vector Pointer constellation is problematical if I stay in scope.
My questions are now:
1. Why the program don't crash while grabbing and processing?
2. and what can i do, that it prevent deleting?
Thanks in advance,
Inge
The reason for why only the last frame is shown is that Mat is a reference-counted class. So when you do something like
Mat vidImg;
vidDev.read(vidImg);
Mat* a = new Mat(vidImg);
a and vidImg are pointing at the same image. So all your elements in your vector are all pointing to the same (last loaded) image. What you want to do is:
Mat a = vidImg.clone();
or in your case (removing the pointers too since they shouldn't be there :) )
vector<Mat> VideoBuffer;
VideoBuffer.push_back(vidImg.clone());
So:
Remove all pointers (shouldn't have them raw anyways), since Mat is already a "handle" type class
use the clone() method to copy the image data.
I believe it might be because you're dereferencing the vector which as you have it is a pointer to a vector and not a vector, rather than the element that it actually contains.
Maybe try changing
vector<Mat*> *VideoBuffer;
to
vector<Mat*> VideoBuffer;
I would also suggest using a vector of smart pointers rather than raw pointers because at the moment your code is leaking memory all over the place. If you stick with the raw pointers you ought to delete each element of the buffer vector before you clear it as clear alone won't deallocate the memory
You'll also need to change
imshow("img",Mat(*(VideoBuffer)[currentVideoFrame]));
to
imshow("img",Mat(*VideoBuffer[currentVideoFrame]));
in the lower while loop
Have you got any loop that calls grabAndProcessFrameVideo() so it shows you all the images?
Could it be that it's showing all your images but really fast so you can only see the last one? If so, add a pause like you have in loadVideoInBuffer() (waitKey(30);) and you should see all the images.
Related
I'm writing a simple multi-threading program to add and access member in a vector in a multiple thread:
Thread 1: Use push_back to add member to vector
Thread 2: Calling a function Iterate through vector and check if the member is already in the vector then return it, otherwise return NULL
Some time I faced the Segmentation fault at the thread 2. Is the vector is thread safety for doing what I mention above. I do not have any code to remove member from the vector, only adding more.
Here is the full code of function iterate the vector:
Scope* ScopeList::FindScope(int32_t domain, int32_t channel) {
Scope* findItem = new Scope(domain, channel);
Scope* resultItem = NULL;
for(uint32_t i = 0U; i < m_scope_list.size(); i++) {
if(m_scope_list.at(i) == NULL) {
continue;
}
if(m_scope_list.at(i)->isEqual(findItem)) {
resultItem = m_scope_list.at(i);
break;
}
}
delete findItem;
findItem = NULL;
return resultItem;
}
Here m_scope_list is a vector of Scope object, which isEqual function is define as follow:
bool Scope::isEqual(Scope* scope) {
if(scope == NULL||!this->m_domain ||!this->m_channel){
return false;
}
bool result = this->m_domain == scope->GetDomain() && this->m_channel == scope->GetChannel();
return result;
}
You need to synchronize both threads. Because a vector is not thread-safe. If you modify the vector from one thread and access from another then there is a high chance of getting a segmentation fault. You might want to look into uniqe_lock or lock_guard and mutex for details. If you don't understand anything about their usages then leave a comment. Happy Multithreading.
EDITED: From comment made by #GianPaolo
push_back will modify the internal state of the vector, in a way that can be not thread safe. if you call push_back when the vector as already reached its capacity, the current T[] array in use will be copied in a new T[] (of higher size), and the original will be deleted. Not something you can safely do while another thread is iterating on the vector
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am programming a Space Invaders clone and I am struggling at creating the bullets.
Whenever I click Space a bullet is supposed to be added to the vector and then I want to move them via a loop, but I dont understand how to create and handle it the proper way.
vector<Bullet> bullets(MAXBULLETS);
int bulletcounter = 0;
while (1) {
Sleep(10);
for (int i = 0; i < sizeof(bullets)-1; i++) {
bullets[i].Move(0, 1);
}
if (GetAsyncKeyState(VK_SPACE)) {
Bullet *bullet = new Bullet();
bullets[bulletcounter] = bullet; // Here is the error
bulletcounter++;
}
bullets is a vector that holds objects of type Bullet.
Bullet *bullet = new Bullet();
bullets[bulletcounter] = bullet; // Here is the error
Your bullet here is of type Bullet*. The two incompatible types get you the error.
To fix this, stop using a pointer and just instantiate an object:
Bullet bullet;
This creates a Bullet object using the parameterless constructor that you can then add to your bullets.
Do note though, that this currently does nothing since you initialize your vector giving it a predefined size bullets(MAXBULLETS), this already creates MAXBULLETS default constructed objects for you, ready to use:
Constructs the container with count default-inserted instances of T.
No copies are made.
Side note : stop using new altogether; this isn't Java or C#. If you need a dynamically allocated object then use a smart pointer. Most of the time, though, an object automatic-storage duration will do just fine.
My proposal
vector<Bullet> bullets;
while (1)
{
Sleep(10);
for (int i = 0; i < bullets.size(); i++)
{
bullets[i].Move(0, 1);
}
if (GetAsyncKeyState(VK_SPACE))
{
bullets.push_back(Bullet());
}
I cannot call a function that does a push_back into a vector
void GameState::InitialiseBullet(float x, float y, float vx, float vy)
{
Bullet* bullets = new Bullet();
bullets->SetSize(5.f, 20.f);
bullets->AddFrame("./images/bullet.png");
bullets->Play();
bullets->SetX(x);
bullets->SetY(y);
bullets->velocityX = vx;
bullets->velocityY = vy;
bullets->isActive = true;
gameObjects.push_back(bullets);
}
when it is inside the following for loop
for (auto& object : gameObjects)
{
//Determine the type at runtime
if (dynamic_cast<Player*>(object) != 0)
{
//Process player-specific logic
PlayerLogic(dynamic_cast<Player*>(object), a_fTimeStep);
}
//Determine the type at runtime
if (dynamic_cast<Bullet*>(object) != 0)
{
//Process bullet-specific logic
BulletLogic(dynamic_cast<Bullet*>(object), a_fTimeStep);
}
if (dynamic_cast<Enemy*>(object) != 0)
{
//Process enemy-specific logic
Enemy* enemy = dynamic_cast<Enemy*>(object);
EnemyLogic(enemy, lowerAliens);
if (enemy->GetIsActive() == true)
{
allDead = false;
}
}
//Update and draw our objects
object->Update(a_fTimeStep);
object->Draw();
}
The piece of code that calls the function:
if (createBullet == true)
{
InitialiseBullet(bulletX, bulletY, 0, 500);
createBullet = false;
}
That code works when outside the for loop. However, I need the for loop to provide access to each of my player, enemy and bullet objects. Is there a way to push_back to a vector inside a for loop that is based on the same vector? I get a "Expression: Vector iterators incompatible" error when it's inside the loop. Any ideas? New to C++ programming.
It looks like you are pushing into the same vector you are iterating, that means, you are forcing items realocation and iterator invalidation; in other words - your data moves to different location and used iterator becomes invalid.
I rarely see situation where you really need to iterate and append same vector, so take a look into your code again.
If you really need to do that, iterate this way:
for (size_t i = 0; i < gameObjects.size(); ++i)
{/*Some code*/}
Also using this method you should use gameObjects[i]. instead of it->
It's just a vector of pointers, so it's not very big.
The objects being added is probably even smaller.
You could make a copy of the vector and iterate over the copy while inserting into the real one.
You could put new items into a new, empty vector while you iterate, and then splice them onto the real one at the end.
To delete objects, you could do either of those things, or you could simply set a flag "isZombie" and then remove all the zombies at the end.
These aren't the only answers, but they all work.
When using iterators to loop through your vector you can't in this 'for-loop' modify the vector.
A quick google gave me this; which seemd to fit your case pretty well.
Probably because the push_back ... caused an internal
reallocation in the vector thus all its iterators were invalidated.
Source: http://www.cplusplus.com/forum/beginner/64854/
Do I understand you right when I'm assuming your using iterators due to your error message.
One question you should ask yourself is why you would ever want to add instances to this vector, maybe you should rethink your design slightly to avoid this.
I don't understand why I get a corrupted heap error with this program (I'm using OpenCV for the class Mat):
class A {
private:
Mat image;
static UINT ThreadProc( LPVOID pParam ) {
A* pThis= (ClientNetwork*)pParam;
UINT nRet= pThis->DoThreadProc(); // get out of 'static mode'
return( nRet );
}
UINT ClientNetwork::DoThreadProc() {
vector<uchar> vect;
while(1) {
/**** initialize vect and get the image data to decode ****/
decode(vect);
}
}
public:
void decode(const vector<uchar>& vectorData){image=imdecode(vectorData, CV_LOAD_IMAGE_COLOR);}
Mat get_image(){return image;}
void start() {m_pcThread= AfxBeginThread(ThreadProc, this );}
}
int main() {
A* a = new A();
a->start();
while(1) {
Mat image = a->get_image();
}
delete a;
return 0;
}
It seems that the error come from Mat image = a->get_image(); because if I return a reference instead of a copy of the object, I don't have error anymore:
Mat* get_image(){return ℑ}
and
Mat* image = a->get_image();
I read that returning a copy of an object is more elegant in C++ than a reference. So I would like to know what is wrong.
EDIT: Visual studio breaks at a->decode(vect) but it happens only when I return an object and not a reference.
EDIT 2:
I edited the code to reflect the full program. I think the problem comes from the shared object a which is copy and modified at the same time. I will see if the problem still occur using a mutex.
You use a without initialising it.
int main() {
A* a;
vector<uchar> vect;
while(1) {
// get the vector of data
a->decode(vect);
Welcome to undefined behaviour, population: you.
Initialise a for a better result.
Then that is the thread sync problem, as you yourself suggested. The image is being constantly filled in in that infinite while loop. And in the middle of it somewhere you try to make a copy of it. Recipe for disaster. You need to take a write lock inside that loop in DoThreadProc, in each iteration. And then you need to take a read lock inside your get_image. You need to use a read/write lock library that does not starve out readers.
Alternatively you could work with mutexes/critical sections. Both that write loop, and that read (get_image) just get exclusive access to image while they are doing their work.
I am curious though - your thread procedure is decoding things in an infinite loop. What are you trying to do in there? And while reading what image do you expect? Any image at that point of time in loop iteration?
The copy constructor of cv::Mat does not create a deep copy of the image. It just creates a reference to the original Mat and increases its reference count.
In the following function of the class, the return statement calls the copy constructor, returning a reference to the original image, which is the probable cause of heap corruption:
Mat get_image(){ return image; }
You should return a deep copy of the image as follows, so that the original image does not get modified accidentally.
Mat get_image(){ return image.clone(); }
I've been creating a class that takes a bunch of images and overlays them onto one BMP. For some reason upon running the code I'm getting a segfault and I've tracked it down to this method. Essentially the if statement checks to see if there is a valid index in the array of images to place this new image in. If it is valid then it deletes whatever was there previously and sets that index to this new Image. The Class is called Scene and is comprised of an array of Image pointers. So what I'm doing is replacing the image that one of those pointers points to. Somehow its not working though. If the pointer is NULL the delete command shouldn't cause any problems, so I don't see what could be going wrong. This code is acting on a Scene that has an array of Image pointers of length 5.
void Scene::addpicture(const char* FileName, int index, int x, int y)
{
if (index<0 || index>maxnum-1)
{
cout << "index out of bounds" << endl;
}
else
{
Image* extra;
extra = new Image;
extra->ReadFromFile(FileName);
delete imagelist[index];
imagelist[index] = extra;
imagelist[index]->xcoord=x;
imagelist[index]->ycoord=y;
}
}
Can anyone help. It would be much appreciated.
Thanks
I've edited to include the constructor:
Scene::Scene(int max)
{
Image** imagelist = new Image*[max];
for(int i=0; i<max; i++)
{imagelist[i] = NULL;}
maxnum = max;
}
I've also commented out the main method so that the only functions being called are
Scene* set = new Scene(5);
set->addpicture("in_01.bmp", 0, 0, 0);
In your constructor you have a local imagelist, but you are using a field imagelist in addpicture. You are shadowing the imagelist field in the constructor and the field never gets initialized.
Fix it by replacing this line:
Image** imagelist = new Image*[max];
With this:
imagelist = new Image*[max];
A SEGFAULT means that you're trying to access a location outside of what you should be. In your comment to Messa, you say that it's happening at the delete command.
So, I ask you: When you construct the Scene class, do you explicitly initialize the pointers in imagelist to NULL? In other words, are there lines like:
for (i=0; i<maxnum; i++) {
imagelist[i] = NULL;
}
in your constructor, or are you assuming that uninitialized arrays start as 0-filled? (Unlike most languages, that assumption is bad in C++.)
This code looks OK, I think error is in some other part of the program. Maybe imagelist array is not initialized to NULL? Or maxnum is not the actual size of imagelist. Or something other.
What exactly is failing - do you have traceback?