Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Pure virtual function call  (Read 3816 times)

0 Members and 1 Guest are viewing this topic.

terminator211

  • Newbie
  • *
  • Posts: 2
    • View Profile
Pure virtual function call
« on: September 23, 2014, 09:56:46 pm »
Hello everyone!

Last time I`ve had an idea to do a project to recording voice on computer A and sending them to computer B (and of course playing them there) in real-time. Of course I used TcpSockets, SoundRecorder and SoundStream. Everything compiles nicely, but the problem occurs when the program is running. I get an "pure virtual function call" in client.exe and "the program stopped working" in server.exe. Here is the code:

server.cpp

#include "SFML/System.hpp"
#include "SFML/Network.hpp"
#include "SFML/Audio.hpp"
#include <iostream>
using namespace std;

void end()
{
        system("pause");
        exit(1);
}

class MyStream : public sf::SoundStream
{
        sf::TcpSocket socket;
        sf::TcpListener listener;
        sf::Int16* samples;
protected:
        virtual void onSeek(sf::Time timeOffset);
        virtual bool onGetData(sf::SoundStream::Chunk& data);
public:
        MyStream();
        ~MyStream();
};

MyStream::MyStream()
{
        unsigned short port = 1234;

        cout << "Oczekiwanie na klienta..." << endl;
       
        if(listener.listen(port) != sf::Socket::Done)
        {
                cout << "Blad przy listen!" << endl;
                end();
        }

        if(listener.accept(socket) != sf::Socket::Done)
        {
                cout << "Blad przy accept!" << endl;
                end();
        }

        cout << "Klient polaczony!" << endl;

        initialize(1, 44100);

}

MyStream::~MyStream()
{
        delete [] samples;
}

void MyStream::onSeek(sf::Time timeOffset)
{
        return;
}

bool MyStream::onGetData(sf::SoundStream::Chunk& data)
{
        size_t received, samples_count;
        delete [] samples;

        if(socket.receive((void*)&samples_count, sizeof(size_t), received)  != sf::Socket::Done)
        {
                cout << "Blad przy odbieraniu ilosci probek!" << endl;
                return false;
        }

        samples = new sf::Int16[samples_count];

        if(socket.receive((void*)samples, samples_count*sizeof(sf::Int16), received) != sf::Socket::Done)
        {
                cout << "Blad przy odbieraniu probek!" << endl;
                return false;
        }

        data.sampleCount = samples_count;
        data.samples = samples;
        return true;
}

int main()
{
        MyStream stream;
        stream.play();
}
 


client.cpp

#include "SFML/System.hpp"
#include "SFML/Network.hpp"
#include "SFML/Audio.hpp"
#include <iostream>
using namespace std;

void end()
{
        system("pause");
        exit(1);
}


class MyRecorder : public sf::SoundRecorder
{
        sf::TcpSocket socket;
public:
        MyRecorder();
protected:
        virtual bool onProcessSamples(const sf::Int16 *samples, std::size_t sampleCount);


};

MyRecorder::MyRecorder()
{
        sf::IpAddress ip = "localhost";
        unsigned short port = 1234;

        cout << "Proba laczenia z serwerem..." << endl;

        if(socket.connect(ip, port) != sf::Socket::Done)
        {
                cout << "Nie udalo sie naweiazac polaczenia!" << endl;
                end();
        }

        cout << "Polaczenie nawiazane!" << endl;
};

bool MyRecorder::onProcessSamples(const sf::Int16 *samples, std::size_t sampleCount)
{
        if(socket.send((void*)sampleCount, sizeof(size_t)) != sf::Socket::Done)
        {
                cout << "Blad przy wysylaniu liczby probek" << endl;
                return false;
        }

        if(socket.send((void*)samples, sampleCount*sizeof(sf::Int16)) != sf::Socket::Done)
        {
                cout << "Blad przy wysylaniu probek" << endl;
                return false;
        }
        return true;
}

int main()
{
       
        MyRecorder recorder;
        recorder.start();

}
 

I`ve also discovered that when I delete the "stream.play()" and "recorder.start()" commands everything works fine (but of course in this case my project is useless). Any suggestions about fixing my problem?

PS. Sorry for my English, but I`m from Poland and I can`t speak English very well. If you want to response, please use as simple words as possible :p

Strelok

  • Full Member
  • ***
  • Posts: 139
    • View Profile
    • GitHub
Re: Pure virtual function call
« Reply #1 on: September 24, 2014, 12:42:18 am »
You should post a minimal example, not your entire class.
Do not use manual memory management, use a std::vector for the samples so that you can resize its size anytime and you can use a lot of utilities a STL container offers.
packets might save you the hassle of using that old style socket.receive overload.
« Last Edit: September 24, 2014, 12:52:22 am by Strelok »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Pure virtual function call
« Reply #2 on: September 24, 2014, 01:09:27 am »
"pure virtual function call" means exactly what it says, a pure virtual function was called. This should never happen and is always a result of programmer error. The detailed explanation can get quite long, and I am notorious for posting walls of text that nobody probably reads, so I will just keep it simple this time ;).

When you inherit from a base class that has pure virtual function as part of its interface, you are overriding that function with your own concrete implementation. At runtime, your application will have to decide which "version" of the function to call, and it does this based on the type of the object. This works out most of the time. The catch is that during construction and destruction of your derived objects, the type of the object changes. Your MyStream object is actually a sf::SoundStream for a split second when you construct it and becomes a sf::SoundStream for a split second when it is being destroyed. The same goes for your MyRecorder object. Taking this into consideration, you don't want to have any virtual function calls inside either your constructor or destructor. You might not have any in your code, but remember that both of those classes rely on threads to do their work behind the scenes and sf::Thread blocks the destruction of the base objects until they have terminated. This means that while your main() is waiting for those objects to be destroyed (which is probably almost the entire time the application is running), they are actually instances of their base classes, and thus the base class's pure virtual functions will be called by the threads.

You need to make sure your main() stays running until the objects are done running. The objects must not be destroyed before their threads terminate.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Pure virtual function call
« Reply #3 on: September 24, 2014, 08:18:02 am »
I am notorious for posting walls of text that nobody probably reads

I read them!  They're the most informative content on this forum.


@terminator: What binary said. You called a pure virtual function somehow, probably in a base class' constructor or destructor.

terminator211

  • Newbie
  • *
  • Posts: 2
    • View Profile
Re: Pure virtual function call
« Reply #4 on: September 24, 2014, 05:00:06 pm »
Thank you very much guys! I`ve forgotten about that play and start functions are suing their separate threads. Now i see my mistake. Thank you :)

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Pure virtual function call
« Reply #5 on: September 24, 2014, 11:04:06 pm »
I am notorious for posting walls of text that nobody probably reads
I read them!  They're the most informative content on this forum.
Me too! Even if I don't understand some of it as it's beyond me  ;D

Just wanted to say that. I don't understand this pure virtual function call nonsense! hehe

p.s. I've learnt so much from a few of the members in this forum posting replies  :)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

 

anything