I have the following classes:
Bar.hpp
#include <string>
class Bar
{
public:
Bar(const std::string& info);
std::string getInfo() { return info; }
protected:
private:
std::string info;
};
Bar.cpp:
#include <Bar.hpp>
Bar::Bar(const std::string& info)
: info(info) { }
Foo.hpp:
#include <string>
#include <vector>
#include <Bar.hpp>
class Foo
{
public:
static void printInfoStore();
static Foo* getFoo(const std::string& name);
Foo() {};
std::string getName() { return name; }
std::vector<Bar> getBars();
void addBar(const std::string& info);
protected:
private:
static std::vector<Foo> infoStore;
Foo(const std::string& name);
std::vector<Bar> bars{};
std::string name;
};
Foo.cpp
#include <iostream>
#include <Foo.hpp>
Foo::Foo(const std::string& name)
: name(name) { }
//static
std::vector<Foo> Foo::infoStore(0);
//static
void Foo::printInfoStore() {
std::cout << "InfoStore is { ";
for (Foo& foo : infoStore) {
std::cout << foo.getName() << "=[ ";
for (Bar& bar : foo.getBars()) {
std::cout << bar.getInfo() << " ";
}
std::cout << "] ";
}
std::cout << " }" << std::endl;
}
//static
Foo* Foo::getFoo(const std::string& name) {
for (Foo& foo : infoStore) {
if (foo.getName() == name) {
return &foo;
}
}
Foo* foo = new Foo(name);
infoStore.push_back(*foo);
return foo;
}
std::vector<Bar> Foo::getBars() {
return bars;
}
void Foo::addBar(const std::string& info) {
Bar* bar = new Bar(info);
bars.push_back(*bar);
}
Basically there is a static vector that holds multiple Foo objects each of which has a vector of Bar objects.
Then I have the following main.cpp:
#include <Foo.hpp>
#include <Bar.hpp>
int main(int argc, char *argv[])
{
Foo::printInfoStore();
Foo::getFoo("Foo1")->addBar("info11"); // info11 is not added to Foo1
Foo::printInfoStore();
Foo::getFoo("Foo1")->addBar("info12");
Foo::printInfoStore();
Foo::getFoo("Foo1")->addBar("info13");
Foo::printInfoStore();
Foo::getFoo("Foo2")->addBar("info21"); // info21 is not added to Foo2
Foo::printInfoStore();
Foo::getFoo("Foo2")->addBar("info22");
Foo::printInfoStore();
return 0;
}
The output is the following:
InfoStore is { }
InfoStore is { Foo1=[ ] }
InfoStore is { Foo1=[ info12 ] }
InfoStore is { Foo1=[ info12 info13 ] }
InfoStore is { Foo1=[ info12 info13 ] Foo2=[ ] }
InfoStore is { Foo1=[ info12 info13 ] Foo2=[ info22 ] }
The strange thing is that the first Bars added for each Foo object (info11 and info21) do not get added. My guess is that there might be a second initialization of the bars vector that happens after the parent Foo object but I don't know if this is the case, nor I can find a rationale behind it.
I tried to initialize the bars vector explicitly within the foo constructor but to no avail: the first Bar added is always discarded.
So why does it happen? What's wrong with my code? What can be done to avoid that behavior?
All of your news are causing memory leaks. None of this code should be using new at all, since none of the vectors are holding pointers.
For that matter, since getFoo() always returns a valid object, whether an existing object or newly-pushed object, it should return a Foo& reference to that object rather than a Foo* pointer (you can return a pointer if you really want to, but I would not advise it).
Either way, you would have to make sure that whatever you do return actually refers to an object that is inside of your vector. Your output is not what you expect because the code is NOT doing this correctly, which is the root of your problem.
When you call getFoo() for a non-existent object, you create a new object, then push a copy of that object into your vector, and then return a pointer to the new'ed object, not a pointer to the copied object. So, any values you subsequently store in the new'ed object appear to be discarded when you print the vector later, since the values don't exist in the copied object that is actually inside of the vector. When you call getFoo() again for an existing object, you return a pointer to the copied object that is inside the vector, and you do not create a new object.
On a similar note, getBars() should also return a reference to its vector, not return a copy of its vector by value.
With all of that said, try something more like this instead:
Bar.hpp
#include <string>
class Bar
{
public:
Bar(const std::string& info);
std::string getInfo() const;
private:
std::string info;
};
Bar.cpp:
#include <Bar.hpp>
Bar::Bar(const std::string& info)
: info(info) { }
std::string Bar::getInfo() const
{ return info; }
Foo.hpp:
#include <string>
#include <vector>
#include <Bar.hpp>
class Foo
{
public:
static void printInfoStore();
static Foo& getFoo(const std::string& name);
std::string getName() const;
std::vector<Bar>& getBars();
const std::vector<Bar>& getBars() const;
void addBar(const std::string& info);
private:
static std::vector<Foo> infoStore;
std::vector<Bar> bars;
std::string name;
Foo(const std::string& name);
};
Foo.cpp
#include <iostream>
#include <Foo.hpp>
Foo::Foo(const std::string& name)
: name(name) { }
//static
std::vector<Foo> Foo::infoStore;
//static
void Foo::printInfoStore() {
std::cout << "InfoStore is { ";
for (const Foo& foo : infoStore) {
std::cout << foo.getName() << "=[ ";
for (const Bar& bar : foo.getBars()) {
std::cout << bar.getInfo() << " ";
}
std::cout << "] ";
}
std::cout << " }" << std::endl;
}
//static
Foo& Foo::getFoo(const std::string& name) {
for (Foo& foo : infoStore) {
if (foo.getName() == name) {
return foo;
}
}
infoStore.push_back(Foo(name));
return infoStore.back();
// or, in C++11..14:
// infoStore.emplace_back(name);
// return infoStore.back();
// or, in C++17 onward:
// return infoStore.emplace_back(name);
}
std::string Foo::getName() const {
return name;
}
std::vector<Bar>& Foo::getBars() {
return bars;
}
const std::vector<Bar>& Foo::getBars() const {
return bars;
}
void Foo::addBar(const std::string& info) {
bars.push_back(Bar(info));
// or, in C++11 onward:
// bars.emplace_back(info);
}
main.cpp
#include <Foo.hpp>
#include <Bar.hpp>
int main(int argc, char *argv[])
{
Foo::printInfoStore();
Foo::getFoo("Foo1").addBar("info11");
Foo::printInfoStore();
Foo::getFoo("Foo1").addBar("info12");
Foo::printInfoStore();
Foo::getFoo("Foo1").addBar("info13");
Foo::printInfoStore();
Foo::getFoo("Foo2").addBar("info21");
Foo::printInfoStore();
Foo::getFoo("Foo2").addBar("info22");
Foo::printInfoStore();
return 0;
}
You store copy in your vector (with memory leaks).
Fixed version:
Foo* Foo::getFoo(const std::string& name) {
for (Foo& foo : infoStore) {
if (foo.getName() == name) {
return &foo;
}
}
return &infoStore.emplace_back(Foo{name});
}
void Foo::addBar(const std::string& info) {
bars.emplace_back(info);
}
Demo
Related
I've run into an issue where a parameter (a user type) I pass into Lua function from C++ causes a crash when the Lua object is destroyed. Note I am using Sol2 in addition to Lua.
I discovered this is happening because Lua appears to be creating a copy of the parameter I passed in, and once the lua object is destroyed, it also destroys that copy. However, one of the member variables of that copy is a pointer to another object. Thus deleting it, deletes the pointer held by the original object, and when accessed causes the crash.
Is there anyway around this? Such as not copying the object but using a pointer to it, or not deleting objects not "owned" by lua/sol2.
I've created a sample project to demonstrate the issue.
LuaWrapper.h
#pragma once
#include <string>
#include <map>
#pragma warning(push, 0)
#define SOL_ALL_SAFETIES_ON 1
#include "sol.hpp"
#pragma warning(pop)
class SharedClass;
class LuaWrapper
{
public:
LuaWrapper();
~LuaWrapper();
public:
void RunFuncWithSharedClassParam(
const SharedClass& shared_class);
protected:
// Returns true if script loaded
bool LoadScriptIfNeeded(
const std::string& file_path);
virtual void RegisterUserTypes(
sol::state& lua_state);
private:
sol::function GetFunction(
const std::string& file_path,
const std::string& function_name);
protected:
typedef std::map<std::string, sol::state> LuaStates;
LuaStates m_lua_states;
private:
// No copies, do not implement
LuaWrapper(const LuaWrapper& rhs) = delete;
LuaWrapper& operator=(const LuaWrapper& rhs) = delete;
};
LuaWrapper.cpp
#include "LuaWrapper.h"
#include "SharedClass.h"
LuaWrapper::LuaWrapper()
{
}
LuaWrapper::~LuaWrapper()
{
std::cout << "~LuaWrapper Called" << std::endl;
}
void LuaWrapper::RunFuncWithSharedClassParam(
const SharedClass& shared_class)
{
sol::function FuncWithSharedClassParam = GetFunction("C:\\Users\\Omega\\source\\repos\\TestingSolution\\x64\\Debug\\LuaFile.lua", "FuncWithSharedClassParam");
if (FuncWithSharedClassParam)
{
FuncWithSharedClassParam(shared_class);
}
}
// Returns true if script loaded
bool LuaWrapper::LoadScriptIfNeeded(
const std::string& file_path)
{
if (!file_path.empty() && m_lua_states.find(file_path) == m_lua_states.end())
{
m_lua_states.emplace(file_path, sol::state());
m_lua_states[file_path].open_libraries(sol::lib::base);
RegisterUserTypes(m_lua_states[file_path]);
sol::protected_function_result result = m_lua_states[file_path].safe_script_file(file_path, &sol::script_pass_on_error);
if (!result.valid())
{
sol::error err = result;
std::string what = err.what();
std::cout << "LuaWrapper::LoadScriptIfNeeded()" << "Failed to load script:" << file_path << " - " << what << std::endl;
return false;
}
return true;
}
return false;
}
void LuaWrapper::RegisterUserTypes(
sol::state& lua_state)
{
lua_state.new_usertype<SharedClass>(
// Lua Class Name
"SharedClass",
// Member Function Binding
"Print", &SharedClass::Print);
}
sol::function LuaWrapper::GetFunction(
const std::string& file_path,
const std::string& function_name)
{
if (!function_name.empty())
{
LoadScriptIfNeeded(file_path);
LuaStates::const_iterator it = m_lua_states.find(file_path);
if (it != m_lua_states.end() && it->second[function_name].valid())
{
sol::function func = it->second[function_name];
return func;
}
}
return NULL;
}
SharedClass.h
#pragma once
class SamplePtr;
#include <string>
class SharedClass
{
public:
SharedClass(
const int id,
const std::string name);
~SharedClass();
void Print() const;
private:
const int m_id;
const SamplePtr* m_ptr;
// Don't create copies, only one instance of this specific object (with this m_id) can exist for the entire program.
SharedClass() = delete;
// Unfortunately, Lua/Sol is using this to copy (commenting out causes compile errors)
//SharedClass(const SharedClass& rhs) = delete;
SharedClass& operator=(const SharedClass& rhs) = delete;
};
SharedClass.cpp
#include "SharedClass.h"
#include "SamplePtr.h"
#include <string>
#include <iostream>
SharedClass::SharedClass(
const int id,
const std::string name) :
m_id(id),
m_ptr(new SamplePtr(name))
{
}
SharedClass::~SharedClass()
{
std::cout << "~SharedClass Called" << std::endl;
delete m_ptr;
}
void SharedClass::Print() const
{
std::cout << "Shared Classs ID: " << std::to_string(m_id) << " (" << m_ptr->m_name << ")" << std::endl;
}
SamplePtr.h
#pragma once
#include <string>
class SamplePtr
{
public:
SamplePtr(
const std::string& name);
const std::string m_name;
private:
SamplePtr() = delete;
SamplePtr(const SamplePtr& rhs) = delete;
SamplePtr& operator=(const SamplePtr& rhs) = delete;
};
SamplePtr.cpp
#include "SamplePtr.h"
SamplePtr::SamplePtr(
const std::string& name) :
m_name(name)
{
}
Main.cpp
#include <iostream>
#include "LuaWrapper.h"
#include "SharedClass.h"
int main()
{
// Once created, this object cannot be modified (const).
const SharedClass* sample0 = new SharedClass(0, "Ptr0");
// Create lua in it's own scope, so it's deleted.
{
LuaWrapper lua;
lua.RunFuncWithSharedClassParam(*sample0);
}
// Try to access sample0's pointer and it's deleted at this point (via the LuaWrapper deletion)...
sample0->Print();
}
LuaFile.lua
function FuncWithSharedClassParam(shared_class)
shared_class:Print();
end
I received a response from the Sol developer, https://github.com/ThePhD/sol2/issues/1340.
Pretty much just need to pass in the pointer for no copy!
I will like to create a struct that holds a higher state for other structs.
I tried to create it like this, but I recently found that returning a pointer to an element of an std::vector is not safe, since that pointer can change.
struct Foo {
std::string &context;
std::string content;
Foo(std::string &context, std::string content) : context(context), content(content) {}
}
struct Bar {
std::string context;
std::vector<std::string> manyFoos;
Foo* addFoo(std::string content) {
manyFoos.emplace_back(context, content);
return &manyFoos[manyFoos.size() - 1];
}
}
struct Example {
Bar bar;
Foo* fooA;
Foo* fooB;
Example() {
fooA = bar.addFoo("Hello");
fooB = bar.addFoo("World");
}
}
What could be a good and safe way of doing this?
What could be a good and safe way of doing this?
Saving the couple (vector reference, Foo's index), assuming Foos are only added at the back.
With a bit of syntaxic sugar:
struct Bar {
std::string context;
std::vector<Foo> manyFoos;
struct FooProxy
{
std::vector<Foo>& foos;
std::vector<Foo>::size_type index;
operator Foo() { return foos[index]; }
};
auto addFoo(std::string content) {
manyFoos.emplace_back(context, content);
return FooProxy{manyFoos, manyFoos.size()-1};
}
};
Live example
You can have vector of shared_ptr & return weak_ptr, this way you can make sure correct referencing
#include <iostream>
#include <vector>
#include <memory>
struct Foo {
std::string &context;
std::string content;
Foo(std::string &context, std::string content) : context(context), content(content) {}
};
struct Bar {
std::string context;
std::vector<std::shared_ptr<Foo>> manyFoos;
std::weak_ptr<Foo> addFoo(std::string content) {
auto foo = std::make_shared<Foo>(context, content);
manyFoos.emplace_back(foo);
return foo;
}
};
void printFoo(std::weak_ptr<Foo> foo)
{
// Here we are checking weak_ptr expiry
std::cout << (foo.expired() ? "Foo Expired" : foo.lock()->content) << std::endl;
}
int main() {
Bar bar;
std::weak_ptr<Foo> fooA;
std::weak_ptr<Foo> fooB;
fooA = bar.addFoo("Hello");
fooB = bar.addFoo("World");
printFoo(fooA);
printFoo(fooB);
// erase last element
bar.manyFoos.pop_back();
printFoo(fooB);
return 0;
}
Output:
Hello
World
Foo Expired
Unexpected behavior of the following program (as short as I could make it):
#include <vector>
#include <iostream>
class Entry;
class CachedPayload {
public:
CachedPayload(const Entry* const o) : owner_(o) {}
void info(const char* where);
private:
const Entry* const owner_;
// meaningful payload not shown in this minimal example
};
class Entry {
public:
Entry(int i) : cached(this), my_i(i) {}
void showEntry(const char* where) const {
std::cout << where << ": this=" << this << ", i=" << my_i << std::endl; }
CachedPayload cached;
private:
int my_i;
};
void CachedPayload::info(const char* where) { owner_->showEntry(where); }
class CachingVector {
public:
CachingVector() {
resize();
data_.at(0).cached.info("GET");
}
void resize() {
data_.push_back(Entry(97));
data_.at(0).cached.info("RSZ");
}
private:
std::vector<Entry> data_;
};
int main()
{
CachingVector vec;
}
Outcome:
$ clang++-6.0 h.cpp && a.out
RSZ: this=0x7ffe1dc52dc8, i=97
GET: this=0x7ffe1dc52dc8, i=4206609
$ g++ h.cpp && a.out
RSZ: this=0x7ffc5e977040, i=97
GET: this=0x7ffc5e977040, i=-578764228
Why is the value of vec.data_[0].my_i, when accessed through vec.data_[0].cached.owner_, overwritten in a nonsensical, compiler-dependent way?
When I merge the two-line implementation of CachingVector::resize() into the constructor CachingVector(), then i=97 stays uncorrupted.
You are storing a pointer to a temporary in your vector (specifically in CachedPayload::owner_). That's the cause of the problem. Once the temporary has been destroyed you have a dangling pointer.
I added this to your code
~Entry() { std::cout << "destroyed " << this << std::endl; }
and this
CachingVector() {
data_.reserve(1); // prevent reallocation
resize();
data_.at(0).cached.info("GET");
}
New output is
destroyed 00000000001AF588
RSZ: this=00000000001AF588, i=97
GET: this=00000000001AF588, i=-858993460
As you can see you are accessing an object which has been destroyed, which is undefined behaviour of course.
To fix this I think you just need to define a copy constructor and assignment operator for Entry that make sure cached.owner_ always has the correct value.
Entry(const Entry& rhs) : cached(this), my_i(rhs.my_i) {}
Entry& operator=(const Entry& rhs) { my_i = rhs.my_i; return *this; }
In the following code, a non-const method of an object calls a const-method of the same object that returns a const-pointer to the object's field, and then this returned pointer is casted to a non-const version — it's a technique similar to one in this answer: Elegant solution to duplicate, const and non-const, getters? [duplicate]. However, since I put pointers into a complex data structure, I am not sure it will actually work. Will it?
class Struct {
private:
Field f, g;
std::map<std::string, const FieldBase*> const_fields_t;
std::map<std::string, FieldBase*> fields_t;
public:
const_fields_t get_fields() const {
return const_fields_t { { "f", &f }, { "g", &g } };
}
fields_t get_fields() {
const Foo* = this;
fields_t result;
foreach(auto& v : const_this->get_fields()) {
result[v->first] = const_cast<FieldBase*>(v->second);
}
return result;
}
};
Yes, (I cleaned up your code a bit):
#include <string>
#include <functional>
#include <iostream>
#include <map>
using namespace std;
class FieldBase {public: virtual string get_data() = 0; };
class Field : public FieldBase { public: string data; virtual string get_data() { return data; } };
class Struct {
public:
Field f, g;
typedef std::map<std::string, const FieldBase*> const_fields_t;
typedef std::map<std::string, FieldBase*> fields_t;
public:
const_fields_t get_fields() const {
cout << "const get_fields() called" << endl;
return const_fields_t { { "f", &f }, { "g", &g } };
}
fields_t get_fields() {
cout << "non-const get_fields() called" << endl;
auto const_this = static_cast<const Struct*>(this);
fields_t result;
for(auto& v : const_this->get_fields()) {
result[v.first] = const_cast<FieldBase*>(v.second);
}
return result;
}
};
int main ()
{
Struct a;
a.f.data = "Hello";
a.g.data = "World";
Struct::fields_t obj = a.get_fields();
cout << obj["f"]->get_data() << endl;
cout << obj["g"]->get_data() << endl;
}
Live example
You basically have the const function act like a gateway to get the values you need and then cast away the constness. That will also work for your purpose since the pointers are going to be de-consted and stored in the new map.
Keep in mind that there might probably be a better solution not involving all the above copying around.
I'm trying to access one of my pointers within my class, however I can't seem to even get VS to acknowledge the pointer is there.
private:
ForwardTo* forward;
and here's how I grab it from the class
ForwardTo& Persons::getForwardTo() const
{
return *forward;
}
The ForwardTo type is an inherited class that typically reads:
class ForwardToTwo : public ForwardTo
{
public:
ForwardToTwo(unsigned int strategy);
virtual std::vector<std::string> forwardMessage(Persons& person, Message& message);
unsigned int getStrategy() const { return strategy;};
private:
unsigned int strategy;
};
and finally, here's how I'm trying to access the pointer
listOfPersons.at(i).getForwardTo()->forwardMessage(listOfPersons.at(i), tempMessage);
This style of access worked previously for my OTHER pointer in my class that acts exactly this same as this one.
While typing the line to access the pointer out in VS, intelliSense picks up all the functions up to getForwardTo(), and after that, the dot operator/arrow operator don't bring up any access to functions.
Thanks again for all help.
(edit, I'm aware the function fordwardMessage() function will return a vector, I was just typing in the VS until intelliSense failed to detect the accessible functions)
(edit 2, I've tried both the . operator and the -> operator, yet neither allow intelliSense to detect any functions.)
(edit 3, additional code:
Here is my Persons Class Header:
#ifndef PERSONS_HPP
#define PERSONS_HPP
#include <string>
#include <vector>
#include <list>
#include <map>
#include "Message.hpp"
#include "TypeOne.hpp"
#include "TypeTwo.hpp"
#include "TypeThree.hpp"
#include "TypeFour.hpp"
#include "TypeFive.hpp"
class ForwardTo;
class ForwardToOne;
class ForwardToTwo;
class ForwardToThree;
class Persons
{
public:
Persons();
~Persons();
void setEmailAddress(std::string email);
std::string getEmailAddress() const;
const std::vector<std::string>& getContactList() const;
void addMessageSeen(Message message);
void addMessageContent(MessageContent mc);
void addInboxMessage(Message message);
void addContact(std::string contact);
void viewContact(const std::vector<std::string>& contacts);
void bumpContact();
void setMessageTypeOne();
void setMessageTypeTwo(unsigned int type);
void setMessageTypeThree(unsigned int quality);
void setMessageTypeFour(unsigned int type, unsigned int quality);
void setMessageTypeFive();
void setForwardTypeOne(unsigned int strategy);
void setForwardTypeTwo(unsigned int strategy);
void setForwardTypeThree(unsigned int strategy);
void printPersonsObj();
std::list<Message> getInbox() const;
MessageType& getForwardWhen() const;
ForwardTo& getForwardTo() const;
private:
std::map<MessageContent, unsigned int> messageList;
std::list<Message> inbox;
std::vector<std::string> contactList;
std::string emailAddress;
ForwardTo* forward;
MessageType* forwardWhen;
};
And here is my Persons.cpp file is:
#include "Persons.hpp"
#include "ForwardToOne.hpp"
#include "ForwardToTwo.hpp"
#include "ForwardToThree.hpp"
#include <iostream>
Persons::Persons()
:emailAddress(""), contactList(), inbox(), messageList()
{
}
Persons::~Persons()
{
//delete forwardWhen;
//delete forwardTo;
}
void Persons::addMessageContent(MessageContent mc)
{
//messageSeen.insert(mc);
}
void Persons::setEmailAddress(std::string email)
{
emailAddress = email;
}
std::string Persons::getEmailAddress() const
{
return emailAddress;
}
void Persons::addContact(std::string contact)
{
contactList.push_back(contact);
}
void Persons::addInboxMessage(Message message)
{
inbox.push_back(message);
}
void Persons::viewContact(const std::vector<std::string>& contacts)
{
for(auto i = contacts.begin(); i != contacts.end(); i ++)
{
std::cout << *i << std::endl;;
}
}
void Persons::setMessageTypeOne()
{
MessageType* forwardWhen = new TypeOne();
}
void Persons::setMessageTypeTwo(unsigned int type)
{
MessageType* forwardWhen = new TypeTwo(type);
}
void Persons::setMessageTypeThree(unsigned int quality)
{
MessageType* forwardWhen = new TypeThree(quality);
}
void Persons::setMessageTypeFour(unsigned int type, unsigned int quality)
{
MessageType* forwardWhen = new TypeFour(type, quality);
}
void Persons::setMessageTypeFive()
{
MessageType* forwardWhen = new TypeFive();
}
void Persons::setForwardTypeOne(unsigned int strategy)
{
ForwardTo* forward = new ForwardToOne(strategy);
}
void Persons::setForwardTypeTwo(unsigned int strategy)
{
ForwardTo* forward = new ForwardToTwo(strategy);
}
void Persons::setForwardTypeThree(unsigned int strategy)
{
ForwardTo* forward = new ForwardToThree(strategy);
}
const std::vector<std::string>& Persons::getContactList() const
{
return contactList;
}
void Persons::bumpContact()
{
std::vector<std::string> tempList = getContactList();
std::string tempContact = tempList.at(0);
for(unsigned int i = 0; i <= tempList.size(); i ++)
{
if(i == tempList.size())
tempList.at(--i) = tempContact;
else
tempList.at(--i) = tempList.at(i);
}
}
void Persons::addMessageSeen(Message message)
{
messageList[*message.getMessageContent()] = message.getMessageContent()->getUniqueID();
}
void Persons::printPersonsObj()
{
std::cout << "PERSONS OBJECT!" << std::endl;
std::cout << "E-mail Address: " << emailAddress << std::endl;
std::cout << std::endl;
}
std::list<Message> Persons::getInbox() const
{
return inbox;
}
MessageType& Persons::getForwardWhen() const
{
return *forwardWhen;
}
ForwardTo& Persons::getForwardTo() const
{
return *forward;
}
Incomplete type normally means that at the point at which you are trying to use getForwardTo, you have not fully declared the ForwardTo class. Indeed in your persons.hop there is only a forward declaration.
Make sure you have included the header that fully declares ForwardTo in the file containing the call site.
getForwardTo() returns a T&, just use the . to access forwardMessage()