I am trying to implement 2 or more classes that are going to use the same shared memory through a wrapper class as a dependency.
My doubt: Can shared pointer substitute Singleton ?
Note: I am trying to avoid Singleton for unit-test purpose.
Below is sample code for reference. Is this implementation fine or violates any C++ Principles?
IShmWrapper.h
#pragma once
class IShmWrapper
{
public:
virtual bool writeToSharedMemory() = 0;
virtual bool readFromSharedMemory() = 0;
};
ShmWrapper.h
#include "IShmWrapper.h"
class ShmWrapper : public IShmWrapper
{
public:
bool writeToSharedMemory() override; //Write operation on shared memory
bool readFromSharedMemory() override;//Read operation on shared memory
};
ShmWrapper.cpp
#include "ShmWrapper.h"
bool ShmWrapper::writeToSharedMemory()
{
//Write operation on shared memory
}
bool ShmWrapper::readFromSharedMemory()
{
//Read operation on shared memory
}
ShmUserA.h
#include "IShmWrapper.h"
#include <memory>
class ShmUserA
{
private:
std::shared_ptr<IShmWrapper> m_shmWrapperA;
public:
ShmUserA(std::shared_ptr<IShmWrapper> shmWrapper);
};
ShmUserA.cpp
#include "ShmUserA.h"
ShmUserA::ShmUserA(std::shared_ptr<IShmWrapper> shmWrapper)
: m_shmWrapperA(std::move(shmWrapper))
{
// Do Additional initialization
}
ShmUserB.h
#include "IShmWrapper.h"
#include <memory>
class ShmUserB
{
private:
std::shared_ptr<IShmWrapper> m_shmWrapperB;
public:
ShmUserB(std::shared_ptr<IShmWrapper> shmWrapper);
};
ShmUserB.cpp
#include "ShmUserB.h"
ShmUserB::ShmUserB(std::shared_ptr<IShmWrapper> shmWrapper)
: m_shmWrapperB(std::move(shmWrapper))
{
// Do Additional initialization
}
Main.cpp
#include<iostream>
#include<IShmWrapper.h>
#include<ShmWrapper.h>
#include<ShmUserA.h>
#include<ShmUserB.h>
int main()
{
std::shared_ptr<IShmWrapper> shmInstance = std::make_shared<ShmWrapper>();
std::unique_ptr<ShmUserA> shmUserA = std::make_unique<ShmUserA>(shmInstance);
std::unique_ptr<ShmUserB> shmUserB = std::make_unique<ShmUserB>(shmInstance);
while(1)
{
//Do Processing of data for incoming requests
}
return 0;
}
Related
There are 1 main class and 3 classes: Main, MLME, MAC and Network.
I would want an MLME object to be created within the MAC object upon calling the constructor of the MAC. Then share the same object to the Network object when calling the Network constructor.
This without making the MLME object global or allocating memory with malloc() or new.
I believe this should be done with references which I don't understand fully. Also there might have to be some initializer-list in Network.cpp? I am more experienced with C than C++ and have tried a lot in order to understand all of this.
This is some of my thoughts of the structure, header and cpp files:
Main.cpp
#include "MAC.h"
#include "Network.h"
int main() {
MAC mac();
Network network(mac);
return 0;
}
Here is the MLME part to be shared:
MLME.h
#ifndef MLME_H_INCLUDED
#define MLME_H_INCLUDED
class MLME {
public:
MLME();
};
#endif
MLME.cpp
#include "MLME.h"
MLME::MLME() {}
The MAC class:
MAC.h
#ifndef MAC_H_INCLUDED
#define MAC_H_INCLUDED
#include "MLME.h"
class MAC {
private:
MLME mlme; // NULLED ?
public:
MAC();
MLME getMLME();
};
#endif
MAC.cpp
#include "MAC.h"
MAC::MAC() {
mlme = MLME:MLME();
}
MLME MAC::getMLME() {
return mlme;
}
The Network class:
Network.h
#ifndef NETWORK_H_INCLUDED
#define NETWORK_H_INCLUDED
#include "MLME.h"
class Network {
private:
MLME& mlme;
public:
Network(MAC mac);
};
#endif
Network.cpp
#include "Network.h"
class MAC;
Network::Network(MAC mac) {
mlme = mac.getMLME();
}
You're close, but:
The Network::Network constructor should take MAC by reference, like so: Network::Network(MAC& mac). Currently you take a copy, which means taking a copy of MLME as well.
In addition, the Network::Network constructor should use an initializer list to initialize mlme. So the full form would be:
Network::Network(MAC& mac) : mlme(mac.getMLME()) {}
MAC::getMLME() should return a reference to MLME: MLME& MAC::getMLME(). Otherwise you return a copy.
The explicit construction of MLME in the MAC constructor is not needed: it is already default-constructed.
You may want to prevent copying of MLME instances by saying MLME(const MLME&) = delete. If it is really a shared resource, you want any changes to go back to the shared instance. Making it impossible to copy MLME instances will prevent you from accidentally making or modifying a copy.
In your main function: MAC mac() does not do what you think it does. Remove the () or you get a "most vexing parse" error.
Main.cpp
int main() {
MAC mac;
Network network(mac);
mac.set(10);
mac.print();
network.print();
mac.set(11);
mac.print();
network.print();
return 0;
}
MLME.h
#ifndef MLME_H_INCLUDED
#define MLME_H_INCLUDED
#include "iostream"
using namespace std;
class MLME {
private:
int i;
public:
MLME();
void print();
void set(int in);
};
#endif
MLME.cpp
#include "MLME.h"
MLME::MLME() {}
void MLME::print() { cout << 'i' << i << endl; }
void MLME::set(int in) {
i = in;
}
MAC.h
#ifndef MAC_H_INCLUDED
#define MAC_H_INCLUDED
#include "MLME.h"
class MAC {
private:
MLME mlme; // NULLED ?
public:
MAC();
MLME& getMLME();
void print();
void set(int in);
};
#endif
MAC.cpp
#include "MAC.h"
MAC::MAC() {
mlme = MLME();
}
MLME& MAC::getMLME() {
return mlme;
}
void MAC::print() {
mlme.print();
}
void MAC::set(int in) {
mlme.set(in);
}
Network.h
#ifndef NETWORK_H_INCLUDED
#define NETWORK_H_INCLUDED
#include "MAC.h"
class Network {
private:
MLME& mlme;
public:
Network(MAC& mac);
void print();
};
#endif
Network.cpp
#include "Network.h"
Network::Network(MAC& mac) : mlme(mac.getMLME()) {}
void Network::print() {
mlme.print();
}
output
i10
i10
i11
i11
I implemented, based on the boost examples, a threadsafe queue-class in the shared memory. It works as expected for a simple producer/consumer model.
As a next step, I defined the interface IConcurrentIPCQueue which is implemented by the ConcurrentIPCQueue class. I need the interface so I can implement an adapter to the queue for another issue.
The only difference between my first version and the current one below is the following:
First version:
template <class T> class ConcurrentIPCQueue
now adding the information, that I want to implement the interface like this:
Current version:
`template <class T> class ConcurrentIPCQueue :public IConcurrentIPCQueue<T>`
results in a read access violation on the consumer side. On the producer side, I can easily push_back and pop_front data correctly on its own. But strangely on the consumer side, I cannot access the shared memory (although the pair from segment.find returns correctly an address and 1).
So the question is, why the version with implementing the interface makes a difference on the consumer side and results in this strange error. And how I can solve it?
To keep the example short, I present here a minimalistic model of the queue:
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/deque.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/thread/lock_guard.hpp>
#include <sstream>
namespace boost_ipc = boost::interprocess;
static char const *SHMEMNAME= "SHMEM";
static char const *SHQUEUENAME= "MYQUEUE";
template <class T> class IConcurrentIPCQueue
{
public:
virtual void push_back(T const & data) = 0;
virtual bool pop_front(T & data) = 0;
virtual unsigned int size() = 0;
};
template <class T> class ConcurrentIPCQueue :public IConcurrentIPCQueue<T>
{
public:
// allocator for allocating memory from the shared memory
typedef boost_ipc::allocator<T, boost_ipc::managed_shared_memory::segment_manager> ShmemAlloc;
typedef boost_ipc::interprocess_mutex IPC_Mutex;
typedef boost_ipc::interprocess_condition IPC_Cond;
typedef boost::lock_guard<IPC_Mutex> LockGuard;
ConcurrentIPCQueue(ShmemAlloc salloc) : mQueue_(salloc) { }
void push_back(T const & data)
{
{
LockGuard lock(mMutex_);
mQueue_.push_back(data);
}
mWait_.notify_one();
}
bool pop_front(T & data)
{
LockGuard lock(mMutex_);
if (mQueue_.empty())
return false;
data = mQueue_.front(); // return reference to first element
mQueue_.pop_front(); // remove the first element
return true;
}
unsigned int size()
{
LockGuard lock(mMutex_);
return mQueue_.size();
}
private:
boost_ipc::deque<T, ShmemAlloc> mQueue_;
IPC_Mutex mMutex_;
IPC_Cond mWait_;
};
typedef ConcurrentIPCQueue<char> myqueue;
void consumer()
{
boost_ipc::managed_shared_memory openedSegment(boost_ipc::open_only, SHMEMNAME);
myqueue*openedQueue = openedSegment.find<myqueue>(SHQUEUENAME).first;
char tmp;
while (openedQueue->pop_front(tmp)) {
std::cout << "Received " << tmp << "\n";
}
}
void producer() {
boost_ipc::shared_memory_object::remove(SHMEMNAME);
boost_ipc::managed_shared_memory mysegment(boost_ipc::create_only, SHMEMNAME, 131072);
myqueue::ShmemAlloc alloc(mysegment.get_segment_manager());
myqueue*myQueue = mysegment.construct<myqueue>(SHQUEUENAME)(alloc);
char mychar='A';
for (int i = 0; i < 10; ++i)
myQueue->push_back(mychar);
while (myQueue->size() > 0)
continue;
}
int main()
{
//producer(); // delete comment for creating producer process
consumer();
return 0;
}
UPDATE:
I could reproduce it with MSVC15.3 and Boost 1.64.
Turns out that the vtable pointers are the issue: they are different in each process, which leads to Undefined Behaviour as soon as you have runtime polymorphic types (std::is_polymorphic<T>).
It turns out the documentation forbids it clearly: Is it possible to store polymorphic class in shared memory?
I am implementing a Visitor class in C++ that generates XML output for a parse tree.
When I compile with Clion on Windows the code compiles but when it runs after it outputs what is expected it crashes. The error code is this
Process finished with exit code -1073741819 (0xC0000005)
When I try to compile using gcc (without Clion) I get the error message
Undefined Reference to 'vtable for PrintXMLVisitor'.
My code is the following. I have distilled it down to the least amount the produces the error
ASTNode.h
#ifndef MINILANG_ASTNODE_H
#define MINILANG_ASTNODE_H
#include <memory>
class Visitor;
class ASTNode {
public:
virtual void accept(std::shared_ptr<Visitor> visitor) = 0;
};
#endif //MINILANG_ASTNODE_H
ASTTypeNode.h
#ifndef MINILANG_ASTTYPENODE_H
#define MINILANG_ASTTYPENODE_H
#include "ASTNode.h"
class ASTTypeNode: public ASTNode {
public:
enum Type {Real, Int, Bool, String};
ASTTypeNode(Type type);
Type getType() const;
void accept(std::shared_ptr<Visitor> visitor) override;
private:
Type type;
};
#endif //MINILANG_ASTTYPENODE_H
ASTTypeNode.cpp
#include "ASTTypeNode.h"
#include "Visitor.h"
ASTTypeNode::ASTTypeNode(ASTTypeNode::Type type)
: type(type)
{
}
ASTTypeNode::Type ASTTypeNode::getType() const {
return type;
}
void ASTTypeNode::accept(std::shared_ptr<Visitor> visitor) {
visitor->visit(std::shared_ptr<ASTTypeNode>(this));
}
Visitor.h
#ifndef MINILANG_VISITOR_H
#define MINILANG_VISITOR_H
#include <memory>
#include "ASTTypeNode.h"
class Visitor {
public:
virtual void visit(std::shared_ptr<ASTTypeNode> typeNode) = 0;
};
#endif //MINILANG_VISITOR_H
PrintXMLVisitor.h
#ifndef MINILANG_PRINTXMLVISITOR_H
#define MINILANG_PRINTXMLVISITOR_H
#include "Visitor.h"
class PrintXMLVisitor: public Visitor {
public:
void visit(std::shared_ptr<ASTTypeNode> typeNode) override;
};
#endif //MINILANG_PRINTXMLVISITOR_H
PrintXMLVisitor.cpp
#include "PrintXMLVisitor.h"
#include <iostream>
void PrintXMLVisitor::visit(std::shared_ptr<ASTTypeNode> typeNode) {
std::string typeName;
switch(typeNode->getType())
{
case ASTTypeNode::Type::Real:
typeName = "Real";
break;
case ASTTypeNode::Type::Int:
typeName = "Int";
break;
case ASTTypeNode::Type::Bool:
typeName = "Bool";
break;
case ASTTypeNode::Type::String:
typeName = "String";
break;
default:
typeName = "Error";
exit(22);
}
std::cout << "<TypeNode>" << typeName << "</TypeNode>" << std:: endl;
}
main.cpp
#include <iostream>
#include "Lexer.h"
#include "ASTTypeNode.h"
#include "PrintXMLVisitor.h"
int main() {
ASTTypeNode astTypeNode (ASTTypeNode::Type::Int);
astTypeNode.accept(std::make_shared<PrintXMLVisitor>());
return 0;
}
Your crafting a shared pointer that isn't dynamic. Specifically,
void ASTTypeNode::accept(std::shared_ptr<Visitor> visitor) {
visitor->visit(std::shared_ptr<ASTTypeNode>(this)); // <=== HERE
}
The this in that statement refers to:
int main()
{
ASTTypeNode astTypeNode (ASTTypeNode::Type::Int); // <== this object
astTypeNode.accept(std::make_shared<PrintXMLVisitor>());
return 0;
}
Changing toolchains isn't going to fix this problem you have options, the two most obvious being:
Stop using a std::shared_ptr for the visit parameter.
Manage all ASTNodeType instances a requiring being std::shared_ptr managed and share from this using the std:enable_shared_from_this capabilities of the standard library.
The former of these is obvious (or at least it is now), so I'll not discuss it further. The latter is not necessarily trivial, as it mandates any instances of your underlying class that utilize shared_from_this must be managed by std::shared_ptr wrappers. I.e., there are no concrete constructions like you're currently doing in main(). This could have significant impact on your overall code base, so choose this carefully.
An example of how the above would work in your case:
First, change the derivation chain of ASTNodeType to look like this:
class ASTTypeNode
: public ASTNode
, public std::enable_shared_from_this<ASTTypeNode> // ADDED
Next, utilize shared_from_this as follows:
void ASTTypeNode::accept(std::shared_ptr<Visitor> visitor)
{
visitor->visit(shared_from_this()); // HERE
}
And finally, honor the warrant you've made that ASTNodeType instances are shared-ptr managed by doing this:
int main()
{
std::shared_ptr<ASTTypeNode> astTypeNode = std::make_shared<ASTTypeNode>(ASTTypeNode::Type::Int);
astTypeNode->accept(std::make_shared<PrintXMLVisitor>());
return 0;
}
That should work. Read more about the things used in the above code here:
std::enable_shared_from_this
std::enable_shared_from_this::shared_from_this
As I said, all of this is to facilitate using a std::shared_ptr from an object given only a this pointer. If you can remove that requirement in the first place, it may be an easier path to take, and I would consider that first.
How can an object access a variable belonging the class containing it?
Right now I have a class called system that contains some other objects, and those objects need to access and modify one of the variables in the System class.
Example:
Class System {
BlockA _blockA = new BlockA();
BlockB _blockB = new BlockB();
BlockC _blockC = new BlockC();
BlockD _blockD = new BlockD();
int myVariable;
...stuff...
}
Class BlockA {
...stuff...
void someFunction () {
System.myVariable++;
}
...stuff...
}
etc...
Alright so I thought about this some more and realized that when initializing the objects, I will pass a pointer to the variable of interest. That way all objects can read that variable. For anyone else with this problem, if you need to write, you'll have to make sure that the variable is atomic.
Hard to know exactly what you're after, but appears something along these lines:
#BlockA.h
#ifndef BLOCKA_H
#define BLOCKA_H
class System;
class BlockA {
System* sys;
public:
BlockA(System* sys) : sys(sys) {}
void SomeFunction();
};
#endif // BLOCKA_H
#BlockA.cpp
#include "System.h"
void BlockA::SomeFunction() {
sys->setMyVariable(sys->getMyVariable() + 1);
}
#System.h
#ifndef SYSTEM_H
#define SYSTEM_H
class BlockA;
class System {
BlockA* _blockA;
int myVariable;
public:
System();
int getMyVariable() const;
void setMyVariable(int value);
BlockA& getBlockA() const;
};
#endif // SYSTEM_H
#System.cpp
#include "System.h"
#include "BlockA.h"
System::System()
: _blockA(new BlockA(this)) { }
int System::getMyVariable() const {
return myVariable;
}
void System::setMyVariable(int value) {
myVariable = value;
}
BlockA& System::getBlockA() const {
return *_blockA;
}
Before I present the code which is found at the bottom of this post I would like to talk about the issue and the fix's that I do not desire. Okay basically I've created a GUI from scratch sort of and one requirement I wanted for this was allow components to have their own click executions so if i click a button or tab etc.. It would call Component->Execute(); Well normally you would do something like a switch statement of ids and if that components ID equaled n number then it would perform this action. Well that seemed kinda dumb to me and I thought there has to be a better way. I eventually tried to incorporate a feature in JAVA where you would do like Component.AddActionListener(new ActionListener( public void execute(ActionEvent ae) { })); or something like that and I thought that this feature has to be possible in C++. I eventually came across storing void functions into a variable in which could be executed at any time and modified at any time. However I hadn't noticed an issue and that was this only worked with static functions. So below you'll see my problem. I've patched the problem by using a pointer to SomeClass however this would mean having an individual function call for every class type is there no way to store a function callback to a non-static class member without doing the below strategy? and instead doing a strategy like the commented out code?
//Main.cpp
#include <iostream> //system requires this.
#include "SomeClass.h"
void DoSomething1(void)
{
std::cout << "We Called Static DoSomething1\n";
}
void DoSomething2(void)
{
std::cout << "We Called Static DoSomething2\n";
}
int main()
{
void (*function_call2)(SomeClass*);
void (*function_call)() = DoSomething1; //This works No Problems!
function_call(); //Will Call the DoSomething1(void);
function_call = DoSomething2; //This works No Problems!
function_call(); //Will Call the DoSomething2(void);
SomeClass *some = new SomeClass(); //Create a SomeClass pointer;
function_call = SomeClass::DoSomething3; //Static SomeClass::DoSomething3();
function_call(); //Will Call the SomeClass::DoSomething3(void);
//function_call = some->DoSomething4; //Non-Static SomeClass::DoSomething4 gives an error.
//function_call(); //Not used because of error above.
function_call2 = SomeClass::DoSomething5; //Store the SomeClass::DoSomething(SomeClass* some);
function_call2(some); //Call out SomeClass::DoSomething5 which calls on SomeClass::DoSomething4's non static member.
system("pause");
return 0;
}
//SomeClass.hpp
#pragma once
#include <iostream>
class SomeClass
{
public:
SomeClass();
~SomeClass();
public:
static void DoSomething3(void);
void DoSomething4(void);
static void DoSomething5(SomeClass* some);
};
//SomeClass.cpp
#include "SomeClass.h"
SomeClass::SomeClass(void)
{
}
SomeClass::~SomeClass(void)
{
}
void SomeClass::DoSomething3(void)
{
std::cout << "We Called Static DoSomething3\n";
}
void SomeClass::DoSomething4(void)
{
std::cout << "We Called Non-Static DoSomething4\n";
}
void SomeClass::DoSomething5(SomeClass *some)
{
some->DoSomething4();
}
Secondary Fix for what I'll do not an exact answer I wanted but it meets my needs for now along with allowing additional features which would have become overly complicate had this not existed.
//Component.hpp
#pragma once
#include <iostream>
#include <windows.h>
#include <d3dx9.h>
#include <d3d9.h>
#include "Constants.hpp"
#include "ScreenState.hpp"
#include "ComponentType.hpp"
using namespace std;
class Component
{
static void EMPTY(void) { }
static void EMPTY(int i) { }
public:
Component(void)
{
callback = EMPTY;
callback2 = EMPTY;
callback_id = -1;
}
Component* SetFunction(void (*callback)())
{
this->callback = callback;
return this;
}
Component* SetFunction(void (*callback2)(int), int id)
{
this->callback_id = id;
this->callback2 = callback2;
return this;
}
void execute(void)
{
callback();
callback2(callback_id);
}
}
The syntax for pointers-to-member-functions is as follows:
struct Foo
{
void bar(int, int);
void zip(int, int);
};
Foo x;
void (Foo::*p)(int, int) = &Foo::bar; // pointer
(x.*p)(1, 2); // invocation
p = &Foo::zip;
(x.*p)(3, 4); // invocation
Mind the additional parentheses in the function invocation, which is needed to get the correct operator precedence. The member-dereference operator is .* (and there's also ->* from an instance pointer).