Error at initializing a member from superclass

I'm trying to implement the observer pattern for learning proposals like it's described in this tutorial:
https://youtu.be/_BpmfnqjgzQ

But I get an error at initializing a member from the IObserver superclass in my subclass:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <iostream>
#include <exception>
#include <vector>
#include <algorithm>
#include <thread>
#include <chrono>

class IObserver;  // formward declaration

class IObservable
{
public:
    virtual void add( IObserver *) = 0;
    virtual void remove( IObserver *) = 0;
protected:
    virtual void notify() = 0;
};

class IObserver
{
public:
    virtual void update() = 0;
protected:
    IObservable * m_observable;
};

class IDisplay
{
public:
    virtual void display() = 0;
};

class WeatherStation : public IObservable
{
public:
    void add( IObserver * to_add ) override {
        if( std::find( m_observers.begin(), m_observers.end(), to_add ) == m_observers.end() )
            m_observers.push_back( to_add );
    }
    void remove( IObserver * to_remove ) override {
        auto itr = std::find( m_observers.begin(), m_observers.end(), to_remove );
        if( itr != m_observers.end() )
            m_observers.erase( itr );
    }

private:
    void notify() override {
        for( auto observer : m_observers ) observer->update();
    }

private:
    void run() {
        while( true ) {
            std::this_thread::sleep_for( std::chrono::seconds(3) );
            notify();
        }
    }
    std::vector<IObserver *> m_observers;
};

class Client : public IObserver, public IDisplay
{
public:
    Client( IObservable * observable)
    : m_observable{ observable }
    {
        m_observable->add( this );
    }
    ~Client() { m_observable->remove( this ); }

    void update() override { display(); }
    void display() override { std::cout << "New notification from server.\n"; }

};


int main()
{
    IObservable * weather_station = new WeatherStation;
    Client client_1( weather_station );
    Client client_2( weather_station );

    delete weather_station;
}

1
2
3
4
weather_station.cpp: In constructor ‘Client::Client(IObservable*)’:
weather_station.cpp:65:7: error: class ‘Client’ does not have any field named ‘m_observable’
   65 |     : m_observable{ observable }
      |       ^~~~~~~~~~~~

Last edited on
I got a workaround by initializing the member variable within constructor's body:
1
2
3
4
5
6
7
8
9
10
    Client( IObservable * observable)
    {
        m_observable = nullptr;
        if( observable != nullptr )
        {
            m_observable = observable;
            m_observable->add( this );
        }
        else throw std::runtime_error("Client::Client(): observable is nullptr.");
    }

Now my code compiles, but I get a segfault.
I am not sure what the problem is, but for the information of others.
These are the errors I get on VS 2017 CE

Exception thrown: read access violation.
this->m_observable->**** was 0xDDDDDDDD. occurred


Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.
This is usually a result of calling a function declared with one calling convention 
with a function pointer declared with a different calling convention. occurred
The value 0xdddddddd means that the memory has been freed.

This is done by the Debug version of the Microsoft CRT library. When you allocate memory it's filled with 0xcdcdcdcd, when it's freed 0xdddddddd , etc.

So the object you're trying to access has been deleted.

Regards

Andy

Win32 Debug CRT Heap Internals
http://www.nobugs.org/developer/win32/debug_crt_heap.html#table
Last edited on
Thank you both. But i must confess that I don't have Windows anymore on my system installed, because I didn't need to use any of its programs, all I need I can do on my Linux distro. And there I'm coding with a simple text editor and a shell. But sometimes I miss a good debugger. Maybe a good graphical debugger would be integrated in the IDE provided by Qt.

I made several changes at my code, and one side effect (to my surprise) was, that the segfaullt error is gone.
Here the final code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <iostream>
#include <exception>
#include <vector>
#include <algorithm>
#include <thread>
#include <chrono>

class IObserver;  // forward declaration

class IObservable
{
public:
    virtual void add( IObserver *) = 0;
    virtual void remove( IObserver *) = 0;
    virtual void run() = 0;
    virtual ~IObservable () {}
protected:
    virtual void notify() = 0;
};

class IObserver
{
public:
    virtual void update() = 0;
protected:
    IObservable * m_observable;
};

class IDisplay
{
public:
    virtual void display() = 0;
};

class WeatherStation : public IObservable
{
public:
    ~WeatherStation() {}

    void add( IObserver * to_add ) override {
        if( std::find( m_observers.begin(), m_observers.end(), to_add ) == m_observers.end() )
            m_observers.push_back( to_add );
        else
           std::cerr << "WetherStation::add(): observer was still previously added.\n";
    }
    void remove( IObserver * to_remove ) override {
        auto itr = std::find( m_observers.begin(), m_observers.end(), to_remove );
        if( itr != m_observers.end() )
            m_observers.erase( itr );
        else
            std::cerr << "WetherStation::remove(): observer was not in the observer list.\n";
    }

    void run() override {
            std::this_thread::sleep_for( std::chrono::seconds(1) );
            notify();
    }

private:
    void notify() override { for( auto observer : m_observers ) observer->update(); }

    std::vector<IObserver *> m_observers;
};

class Client : public IObserver, public IDisplay
{
public:
    Client( IObservable * observable) { m_observable = observable; m_observable->add( this ); }
    ~Client() { m_observable->remove( this ); }

    void update() override { display(); }
    void display() override {
        std::cout << "Object " << this << ": New notification from observervable.\n";
    }

};


int main()
{
    IObservable * weather_station = new WeatherStation;

    Client client_1( weather_station );
    Client client_2( weather_station );

    while( true ) weather_station->run();
    delete weather_station;
}
Last edited on
> the segfaullt error is gone.
you are just unlucky

virtual ~IObservable () {}
quite an important change, otherwise delete weather_station; will not call `WeatherStation' destructor
¿but why do you do delete new T?
1
2
WeatherStation weather_station;
Client client_1( &weather_station );



another issue ~Client() { m_observable->remove( this ); }
¿are you sure that `m_observable' is valid? (hint: it is not, you delete it on line 87)



> I got a workaround by initializing the member variable within constructor's body:
you can't put it in the initializer list because at that point `m_observable' was already constructed by the constructor of IObservable
you may let the parent manage its own variables
1
2
Client(IObservable *observable):
   IObserver(observable){}

Last edited on
Thank you for your hint, ne555.
Topic archived. No new replies allowed.