Multiple data types within one vector of pointers using templates - oop

I have two classes seen below,
template <typename T> class node {
public:
int NodeID;//ID used to identify node when inserting/deleting/searching
T data;//generic data encapsulated in each node.
std::vector<node*> children;//child nodes, list of ptrs
std::vector<node*> parents;//parent nodes list of ptrs
};
template<typename T> class DAG {//Class for the graph
std::vector<node<T>*> Nodes;//Vector of node ptrs, this is how we define a DAG;
}
I was wondering whether its possible using templates to have the vector of nodes contain nodes of multiple types? Something like this.
std::vector<node*> Nodes = {node<int>*,node<string>*, ...}

I suggest that you use polymorphism and create a non-template base class:
struct nodebase {
nodebase(int id) : NodeID{id} {}
virtual ~nodebase() = default; // to be able to delete via base class pointer
virtual void print(std::ostream& os) const {
os << NodeID;
}
int NodeID; // ID used to identify node when inserting/deleting/searching
std::vector<std::unique_ptr<nodebase>> children; // child nodes, list of ptrs
std::vector<nodebase*> parents; // parent nodes list of ptrs
};
// to be able to print all nodes, calls the overridden `print` method:
std::ostream& operator<<(std::ostream& os, const nodebase& nb) {
nb.print(os);
return os;
}
With that base class, your node<T> could look like this:
template <typename T>
class node : public nodebase {
public:
// constructor taking `id` + the arguments needed for `T`:
template<class... Args>
node(int id, Args&&... args) : nodebase{id}, data{std::forward<Args>(args)...} {}
void print(std::ostream& os) const override {
nodebase::print(os);
os << ',' << data;
}
T data; // generic data encapsulated in each node.
};
And you could use it like so:
int main() {
std::vector<std::unique_ptr<nodebase>> Nodes;
Nodes.emplace_back(std::make_unique<node<int>>(1, 12356));
Nodes.emplace_back(std::make_unique<node<std::string>>(2, "Hello world"));
for(auto& ptr : Nodes) {
std::cout << *ptr << '\n';
}
}
Output:
1,12356
2,Hello world

Related

How to Serialize Custom Objects in Qt6

I have a custom class Dummy which I want to send as an object using Dynamic Replica in Qt6. I'm able to send the class but it's being transferred as QVariant which I'm not able to extract(or cast) from QVariabnt object.
Below is my implementation:
Dummy.h file
#ifndef CLIENT_DUMMY_H
#define CLIENT_DUMMY_H
#include <QtCore/qobject.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qvariant.h>
#include <QtCore/qmap.h>
#include <QtCore/qmetatype.h>
#include <QtRemoteObjects/qremoteobjectnode.h>
#include <QtRemoteObjects/qremoteobjectsource.h>
#include <QtCore>
class Dummy {
Q_GADGET
Q_PROPERTY(QString m_name READ name WRITE setName)
public:
Dummy(){}
explicit Dummy(QString str) : m_name(str) {}
QString name() const {
return m_name;
}
void setName(QString str){
m_name = str;
}
~Dummy() = default;
private:
QString m_name;
};
Q_DECLARE_METATYPE(Dummy)
inline QDataStream &operator<<(QDataStream &ds, const Dummy &obj) {
QtRemoteObjects::copyStoredProperties(&obj, ds);
return ds;
}
inline QDataStream &operator>>(QDataStream &ds, Dummy &obj) {
QtRemoteObjects::copyStoredProperties(ds, &obj);
return ds;
}
inline bool operator==(const Dummy &left, const Dummy &right) Q_DECL_NOTHROW {
return left.name() == right.name();
}
inline bool operator!=(const Dummy &left, const Dummy &right) Q_DECL_NOTHROW {
return !(left == right);
}
inline QDebug operator<<(QDebug dbg, const Dummy &obj) {
dbg.nospace() << "Dummy(" << "m_name: " << obj.name() << ")";
return dbg.maybeSpace();
}
The class is present at both sides server as well as client.
.rep file
class Interface {
PROP(Dummy dummy);
[...removed extra code]
}
Server method sending data to client:
void send() {
Dummy dummy("DummyString");
setDummy(dummy);
}
Client side file:
Inside constructor:
QObject::connect(reptr.data(), SIGNAL(dummyChanged(Dummy)), this, SLOT(receiveDummy(Dummy)));
void DynamicClient::receiveDummy(Dummy dummy) {
if(reptr.data()->isReplicaValid()){
QVariant variant = reptr.data()->property("dummy");
qDebug() << variant;
}
}
But when object from server to client is sent, qDebug() prints below:
QVariant(Dummy, QVariant(QString, "DummyString"))
I'm not able to extract Dummy Object from Qvariant object.
I've tried registering my custom type using qRegisterMetaType() as well but still it didn't work. Apart from that, I've used qvariant_cast and variant.value() but I printed the value I get some random character each time.
Thanks in advance. I can post more code if required.
Turns out I was not registering the Dummy class on client side due to which client was not able to recognize the type.
qRegisterMetaType needs to be used at both ends.

How to implement overloading of assignment operators in C++?

I am trying to use assignment operator overloading to perform deep copy but not able to figure out the right way to do it. I have a Class Computer and need to use it to copy its object to that of class Laptop.
It should look something like this:
#include <algorithm>
class SomeClass {};
class AnotherClass {};
class Computer
{
public:
Computer() :
m_someclass(new SomeClass()),
m_double(0.0)
{
}
virtual ~Computer()
{
delete m_someclass;
}
Computer(const Computer& other) :
m_someclass(new SomeClass(*other.m_someclass)),
m_double(other.m_double)
{
}
Computer& operator=(const Computer& other)
{
if (this != &other)
{
Computer tmp(other);
swap(tmp);
}
return *this;
}
void swap(Computer& other) noexcept // or throw() for before c++11
{
std::swap(m_someclass, other.m_someclass);
std::swap(m_double, other.m_double);
}
private:
SomeClass* m_someclass;
double m_double;
};
class Laptop : public Computer
{
public:
Laptop() :
m_anotherclass(new AnotherClass()),
m_int(0)
{
}
virtual ~Laptop()
{
delete m_anotherclass;
}
Laptop(const Laptop& other) :
Computer(other),
m_anotherclass(new AnotherClass(*other.m_anotherclass)),
m_int(other.m_int)
{
}
// Create a Laptop object from a Computer object
explicit Laptop(const Computer& other) :
Computer(other),
m_anotherclass(new AnotherClass()),
m_int(0)
{
}
Laptop& operator=(const Laptop& other)
{
if (this != &other)
{
Laptop tmp(other);
swap(tmp);
}
return *this;
}
// Assign a laptop object from a computer object.
Laptop& operator=(const Computer& other)
{
if (this != &other)
{
Laptop tmp(other);
swap(tmp);
}
return *this;
}
void swap(Laptop& other) noexcept // or throw() for before c++11
{
Computer::swap(other);
std::swap(m_anotherclass, other.m_anotherclass);
std::swap(m_int, other.m_int);
}
private:
AnotherClass* m_anotherclass;
int m_int;
};
int main()
{
Computer computer;
// Construct a new Laptop object by copying data from a Computer object
Laptop laptop1(computer);
// Assign Computer data in Laptop to that of a Computer object
Laptop laptop2;
laptop2 = computer;
}
For non-pointer member variables, you just perform a standard copy with operator=. For pointer member variables (that the object owns), you use the new operator and construct it with the pointer that the other object has.

Boost serialization and pointers to parent class

Assuming the following simplified code:
Parent class
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/unique_ptr.hpp>
class Parent
{
public:
Parent();
...
private:
// boost serialization
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & *m_child;
}
std::unique_ptr<Child> m_child;
}
Parent::Parent()
{
...
m_child = std::unique_ptr<Child>(new Child(this));
}
Child class
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/unique_ptr.hpp>
class Child
{
public:
Child(Parent * parent)
{
m_parent = parent;
};
...
private:
// boost serialization
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & m_parent;
}
Child(){};
Parent m_parent{ nullptr };
}
My parent class creates a child class and passes a pointer to itself stored by the child.
When archiving the parent class, it archives the child which archives the pointer to the parent.
When restoring the parent class, it creates the child class and restores it as well. My question is this:
Will the pointer in the child class get restore properly so it is guaranteed to point to it's parent?
This SEEMS to work which I've verified by stepping through the debugger and comparing the values of the Parent's this pointer with the child's m_parent. However, I can't figure out how boost pulls this off and it makes me wonder if I'm just 'getting lucky'. Can anyone verify that boost serialization is smart enough to maintain the child::m_parent->parent relationship?
Or should I be taking the extra step of not archiving the pointer and setting it after loading the object?
Two things:
Object Tracking facilitates this. Object Tracking is enabled by default when serializing pointers.
No, you do not serialize the unique_ptr like that.
In fact, there's little reason to serialize the m_parent of the child, either, because the parent can set the self-reference from within the load handler.
But assuming that you want the easy way, let's stick with that idea and make it work due to Object Tracking
DEMO
I included some tricks to demonstrate that deserialization
correct de-duplicates pointers to the same object
restores the member pointers even if we forcefully "break" the invariants prior to deserialization
Live On Coliru
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/unique_ptr.hpp>
#include <memory>
#include <sstream>
#include <iostream>
class Parent;
class Child {
public:
Child(Parent *parent)
: m_parent(parent), m_duplicate_parent(parent) {}
Parent *m_parent { nullptr };
Parent *m_duplicate_parent{ nullptr };
private:
friend class boost::serialization::access;
template <class Archive> void serialize(Archive &ar, unsigned) {
ar & m_parent & m_duplicate_parent;
}
Child() = default;
};
class Parent {
public:
Parent() : m_child(std::make_unique<Child>(this)) {}
//private:
friend class boost::serialization::access;
template <class Archive> void serialize(Archive &ar, unsigned) {
ar & m_child;
}
std::unique_ptr<Child> m_child;
};
int main() {
std::stringstream ss;
{
boost::archive::text_oarchive oa(ss);
Parent p;
assert(&p == p.m_child->m_parent);
assert(&p == p.m_child->m_duplicate_parent);
oa << p;
}
std::cout << ss.str();
{
boost::archive::text_iarchive ia(ss);
Parent p;
// let's purposelly break the invariants so we know deserialization
// does restore them as required, and we not just "getting lucky":
p.m_child->m_parent = nullptr;
p.m_child->m_duplicate_parent = nullptr;
assert(&p != p.m_child->m_parent);
assert(&p != p.m_child->m_duplicate_parent);
// nuclear:
p.m_child.reset();
// now deserialize
ia >> p;
assert(&p == p.m_child->m_parent);
assert(&p == p.m_child->m_duplicate_parent);
}
}
Prints something similar to
22 serialization::archive 15 1 0
0 0 0 2 1 0
1 0 0 0 0

Why is this subclass' parent method call not polymorphic?

I've been dabbling in Dlang recently as C++ just wasn't quite sitting right with me after having used Python for so long. While dabbling, I came across what I thought would be a very simple exercise in polymorphism. I suppose how you would expect something to work and what it actually does are two entirely different things for reasons an end user probably can't comprehend. That being said, here is the source code of my "sandbox.D":
import std.stdio;
class Animal {
string voice = "--silence--";
void speak() {
writeln(this.voice);
}
}
class Dog : Animal {
string voice = "Whoof!";
}
int main() {
auto a = new Animal();
auto d = new Dog();
writeln(a.voice); // Prints "--silence--"
writeln(d.voice); // Prints "Whoof!"
a.speak(); // Prints "--silence--"
d.speak(); // Prints "--silence--" NOT "Whoof!"
return 0;
}
I guess my issue is why the "this" keyword just doesn't seem to be functioning how you would expect it to in the C++ successor language.
Methods are polymorphic, variables aren't. So instead of making the voice a variable, you want to override speak in the child.
Also, the auto return type doesn't work with polymorphism, you need to actually specify the types. (The reason is that auto return makes a function template in the compiler, which in theory could have multiple overridable slots in the function table, so it just doesn't try to put it in.)
So try this out:
import std.stdio;
class Animal {
void speak() { // changed to void instead of auto
writeln("--silence--");
}
}
class Dog : Animal {
override void speak() { // the override tells it to override the base method
writeln("woof");
}
}
int main() {
auto d = new Dog();
d.speak();
return 0;
}
If you have a lot of shared functionality and want to reuse one function with slight changes in child classes, you might make a method instead of a variable that just returns something.
Like string voice() { return "woof"; }, then it can be overridden in children.
Another way is to use template this parameter:
import std.stdio;
class Animal {
string voice;
void speak(this C)() {
writeln((cast(C)this).voice);
}
}
class Dog : Animal {
string voice = "Whoof!";
}
int main() {
auto a = new Animal();
auto d = new Dog();
a.speak(); // Prints ""
d.speak(); // Prints "Whoof!"
return 0;
}
Or when you do not need to have voice as a member:
import std.stdio;
class Animal {
static immutable voice = "";
void speak(this C)() {
writeln(C.voice);
}
}
class Dog : Animal {
static immutable voice = "Whoof!";
}
int main() {
auto a = new Animal();
auto d = new Dog();
a.speak(); // Prints ""
d.speak(); // Prints "Whoof!"
return 0;
}

segfault happens when I serialize nested class in apache module

Serializing simple class "A" in Apache module done without error but when I tried to serialize my complex object like "X" which has a member, type of "A", I got segfault in Apache module. ( this doesn't happen to a executable console application )
------------------------- here is my code : ---------------------
class A {
private:
friend class boost::serialization::access; // to enable boost "access" class to call private "serialize" method of class "A"
template<class ArchT>
void serialize(ArchT &ar, unsigned int version) { // method for both serializing and deserializing
ar & memA; // (de)serialize member "memA"
}
std::string memA; // sample member
public:
A(){}
A(std::string pmemA) :
memA(pmemA) {
}
std::string GetMemA()
{
return memA;
}
};
class X {
private:
friend class boost::serialization::access;
template<class ArchT>
void serialize(ArchT &ar, unsigned int version) {
ar & memX;
ar & a;
}
std::string memX;
A a;
public:
X(std::string pmemX, A pa) :
memX(pmemX), a(pa) {
}
X(){}
};
-------------------
string st=GetRandomFileName();
ofstream out(st.c_str());
boost::archive::text_oarchive out_r(out);
A a("Amem");
X x("Xmem", a);
out_r << x; // not works
out_r << a; // works!
------------------- here is stack trace from gdb for apache ----------------
boost::serialization::typeid_system::extended_type_info_typeid_0::is_less_than(boost::serialization::extended_type_info const&) const () from /tmp/libIRSProWebApacheModule.so
2 0xb7223c61 in std::_Rb_tree