I have the following code (live on Coliru):
// untouchable extern library .hpp file
typedef union ExternLibraryUnion
{
int a;
float b;
}ExternLibraryUnion;
// my code
#include <iostream>
class Container{
public:
Container() : m_union(NULL) {};
~Container(){
if(m_union){
delete m_union;
}
}
void init(){
m_union = new ExternLibraryUnion();
}
ExternLibraryUnion* get_union(){
return m_union;
}
private:
ExternLibraryUnion* m_union;
};
class Master{
public:
Master() : m_union(NULL) {
m_container.init();
};
~Master(){
if(m_union){
delete static_cast<ExternLibraryUnion*>(m_union);
}
}
void load(){
}
void set(int i){
m_union = m_container.get_union();
m_union->a = i;
}
void* get_union(){
return m_union;
}
private:
void* m_union;
Container m_container;
};
class Worker{
public:
Worker() : m_extern_library_union(NULL) {};
~Worker(){
if (m_extern_library_union){
delete m_extern_library_union;
}
}
void load(Master& master){
m_extern_library_union = reinterpret_cast<ExternLibraryUnion*>(master.get_union());
}
int get_int(){
return m_extern_library_union->a;
}
private:
ExternLibraryUnion* m_extern_library_union;
};
int main()
{
Master master;
master.set(3);
Worker worker;
worker.load(master);
std::cout << worker.get_int() << std::endl;
}
The code produces:
main.cpp: In member function 'void Master::set(int)':
main.cpp:55:16: error: 'void*' is not a pointer-to-object type
m_union->a = i;
^~
In an extern library, a union ExternLibraryUnion is defined which I'm using inside my own code. My problem, which I can't get my head around, is in the set method of class Master. The Master member void* m_union should point to the union stored inside the member Container m_container. As I'm setting the m_union = m_container.get_union() the compiler should be able to know that I'm getting a ExternLibraryUnion* back from the get_union() method call. So I don't quite the error arising from the assignment m_union->a = i. Sure, a void* has no type, but I assigned it a pointer of the precise type ExternLibraryUnion.
Let's also say I can not touch the Container m_container object directly. I need to make the assigned through the void* m_union pointer.
Any help is highly appreciated!
The compiler has no clue what m_union might actually be pointing at. You declared it as a void * so the compiler believes you, it has no choice. And that's all it knows, so m_union->a has to be flagged as an error, because ->a has no meaning to the compiler here.
To put it another way, RTTI aside, pointers don't 'know' what they're pointing at. The compiler only knows how the pointer was declared.
I don't know what else to say, it's really that simple. I don't like having to say this, but looking at the code as a whole, it looks like a complete mess. Who wrote it?
[Edit] And what Jeffrey said will indeed fix it, but that's not what you asked.
You need to change
private:
void* m_union;
to
private:
ExternLibraryUnion* m_union;
at line 63. As your code stand, you upcast the pointer to void*, and then, at the next line the compiler can't know the pointed type.
If you can't change the type, you can static_cast the void pointer to an
ExternLibraryUnion*. Then use that to access. Since you know the type, the static_cast could be "acceptable". But not the nicest design by any measure.
Related
Let's say I have a class PArr which stores an array of various classes StringWrapper, FloatWrapper, IntWrapper- all of them derive from a base class Wrapper.
It's PArr class:
class PArr{
private:
Wrapper** _wrappers;
int _size;
public:
PArr(int size);
Wrapper& operator[](int index);
};
And here's the implementation of this class
#include "PArr.h"
PArr::PArr(int size){
_size = size;
_wrappers = new Wrapper*[_size];
}
Wrapper& PArr::operator[](int index){
return _wrappers[index];
}
And here's the class for example FloatWrapper
#pragma once
#include "Wrapper.h"
class FloatWrapper : public Wrapper{
private:
float* _floatPtr;
public:
FloatWrapper(float number);
};
My main method looks like this:
int main() {
PArr a(3);
a[0] = new FloatWrapper(0.1);
}
I get an error:
"no match for 'operator=' (operand types are 'Wrapper' and 'FloatWrapper*')
What am I doing wrong?
At the risk of stating the obvious: your operator[] is returning a Wrapper&, which is a reference type, and you're trying to assign a Wrapper*, a pointer type to it. This ain't gonna work.
If you rewrote your main function slightly, say like this:
int main()
{
PArr a(3);
auto k = a[0];
}
you might find the error more informative:
main.cpp: In member function 'Wrapper& PArr::operator[](int)':
main.cpp:27:27: error: invalid initialization of reference of type 'Wrapper&' from expression of type 'Wrapper*'
return _wrappers[index];
~~~~~~~~~~~~~~~^
You might try something like this instead:
Wrapper*& PArr::operator[](int index)
{
return _wrappers[index];
}
which does compile and let your original main run, at least for me. I make no further promises.
Finally, this answer isn't the place to go into the deeper problems with your code (use smart pointers, use standard library container classes like array or vector, consider things like std::any or std::variant), but, y'know, you should read up on those things.
I'm implementing a class that performs type erasure for small objects and have encountered a segmentation fault which I do not understand.
The following program:
#include <iostream>
#include <type_traits>
struct small_object
{
public:
template<class T>
small_object(const T& value)
{
new(&storage_) concrete<T>(value);
}
~small_object()
{
get_abstract().~abstract();
}
void print() const
{
// XXX crash here
get_abstract().print();
}
private:
struct abstract
{
virtual ~abstract(){}
virtual void print() const = 0;
};
template<class T>
struct concrete
{
concrete(const T& value) : value_(value) {}
void print() const
{
std::cout << value_ << std::endl;
}
T value_;
};
abstract& get_abstract()
{
return *reinterpret_cast<abstract*>(&storage_);
}
const abstract& get_abstract() const
{
return *reinterpret_cast<const abstract*>(&storage_);
}
typename std::aligned_storage<4 * sizeof(void*)> storage_;
};
int main()
{
small_object object(13);
// XXX i expect this line to print '13' to the terminal but it crashes
object.print();
return 0;
}
Crashes at the lines indicated by XXX.
I believe the issue is that the virtual call to .print() is not being dynamically dispatched correctly, but I don't understand why.
Can anyone tell what am I missing?
You didn't derive concrete<T> from abstract, so no vtable is being created when you construct the object using placement new. Therefore, when you try to invoke the virtual function, it will fail; concrete<T> and abstract are actually completely unrelated types in this example.
I would recommend using the override keyword if you're using C++11 or newer to allow the compiler to generate an error in cases like this.
std::aligned_storage<4 * sizeof(void*)> storage_;
This creates storage of one byte.
The template argument does not set the size of the declared object, but rather the size of an object that can be allocated in a suitably-sized array of this type. Hence, you need
std::aligned_storage<4 * sizeof(void*)> storage_[4 * sizeof(void*)];
GCC 6.2.0 warns you about this:
warning: placement new constructing an object of type ‘small_object::concrete<int>’ and size ‘16’ in a region of type ‘std::aligned_storage<32ul>’ and size ‘1’ [-Wplacement-new=]
(You still need to derive concrete from abstract).
I have a class called sender with private attribute isSending and a friend function sending. Inside the friend function, I want to access the isSending attribute
class sender{
private:
isSending=false;
friend void* sending (void * callerobj);
}
void* sending (void * callerobj){
while(<isSending is true>){
}
}
I've tried
callerobj->isSending
callerobj.isSending
But I got compile error. How can I access isSending from a friend function with (void * callerobj) parameter?
Since the type of callerobj is void*, you cannot use it to access any member data or member function. After all, the original object could be an int*.
If you are sure that the original object is a sender*, you can cast callerobj to sender* and then use it to access its member data.
sender* senderobj = reinterpret_cast<sender*>(callerobj);
if ( senderobj != nullptr )
{
while ( senderobj->isSending )
{
...
}
}
Since compiler doesn't know what void* is I mean is it sender* or any thing else compiler doesn't know that. So it can't access the isSending
try replacing void* with sender* in definition and prototype of sending function. or if you use c++11 use auto* instead of void*. or you can also cast the void* to the object of type sender*.
Note: You'll have to be sure the callerObj is of type sender*
Here is one way, combining (ugh) reinterpret_cast and dynamic_cast. In general, void* is seldom necessary in modern C++, use e.g. auto or other language mechanisms to avoid the C-style type unsafety.
#include <iostream>
using std::cout;
class Base
{
public:
virtual void a_virtual_fcn() = 0;
};
// Need to inherit from Base to get real run-time cast below
class SomeClass : public Base
{
public:
SomeClass() : is_sending(false) {}
void a_virtual_fcn() {}
private:
bool is_sending;
friend int main();
};
int main()
{
SomeClass sc;
void* vp = ≻
if ( dynamic_cast<SomeClass*>(reinterpret_cast<Base*>(vp)) ) {
cout << "is sending " << sc.is_sending << '\n';
}
return 0;
}
Following is some example code for using "member variable pointer".
#include <iostream>
using namespace std;
struct CData {
int m_x;
int m_y;
};
int main() {
CData obj = {10, 20};
int CData::*pData = &CData::m_x;
cout << obj.*pData << endl;
return 0;
}
http://ideone.com/hJyWP9
From this example, I am not quire sure when I should use the member variable pointer.
Could you inform me some benefits or example of using the member variable pointer?
I think this is much more useful for functions rather than variable members, but the same principal applies to both.
Say I have a class with 3 functions that do one thing which depends on something such as the processor you are running with (i.e. INTEL versus AMD, or processor that supports SSE4 versus an older process with only SSE2...)
void renderCPU();
void renderSSE2();
void renderSSE3();
void renderSSE4();
Then you'd take the pointer of one of these functions and use the pointer instead of testing whether you have SSE4, SSE3, SSE2, or CPU each time you want to render.
// in constructor
if (SSE4) render_ptr = &C::renderSSE4;
else if (SSE3) render_ptr = &C::renderSSE3;
else if (SSE2) render_ptr = &C::renderSSE2;
else render_ptr = &C::renderCPU;
// And in the render function:
this->*render_ptr();
For variable members, similar things could happen, although frankly I never used that for a variable, probably because you can also use a straight pointer (i.e. an 'int *' in your example...) Although I guess it would be a good idea to use class pointers for added security.
Now, I recall, a while back, using a class with a public const reference pointer to a variable member that was private. In effect, it was giving the user a getter() without having to actually call a function. One problem with that technique is that the reference is locked on construction.
class P
{
private:
int v_;
public:
const int& value;
p()
: value(v_) // locked...
{
}
};
A class variable pointer would allow you to change the pointer while using the object.
class P
{
private:
int x_;
int y_;
int z_;
public:
const int P::*ref;
p()
: ref(&P::x_) // not locked...
{
}
void modeX()
{
ref = &P::x_;
}
void modeY()
{
ref = &P::y_;
}
void modeZ()
{
ref = &P::z_;
}
};
With such a class you should be able to do something like:
P p;
cout << p.*p.ref; // write x_
p.modeZ();
cout << p.*p.ref; // write z_
This makes 'value' quite safe, opposed to a bare pointer.
Note also that gives you the ability to write the following:
P p, q;
p.*q.ref = q.*p.ref;
Which may be useful to some people...
AbstractFieldCollection is the base class of hardwareMissingAlarm, etc.
hardwareMissingAlarm belongs to another class that is a template.
alarmFieldCollection.push_back((AbstractAlarmField Device::*) &Device::hardwareMissingAlarm);
alarmFieldCollection.push_back((AbstractAlarmField Device::*) &Device::hardwareErrorAlarm);
alarmFieldCollection.push_back((AbstractAlarmField Device::*) &Device::badConfigAlarm);``
Then in another function I'm reading the vector like this:
for(int32_t i=0; i<alarmFieldCollection.size(); i++)
{
AbstractAlarmField Device::* pAF = alarmFieldCollection[i];
std::cout << "isRaised: "<< pDev << std::endl;
if ((pDev->*pAF).isRaised(pContext))
{
.....
}
}
and pDev is the Device object, however pDev->*pAF returns NULL. In fact when I'm printing &Device::hardwareErrorAlarm, &Device::hardwareMissingAlarm the result is 1. I don't know what I'm doing wrong.
isRaised is a method that belongs to the class AbstractAlarmField.
Thanks in advance.
You provided almost no code but it seems like you are storing an abstract object by value, not by reference or pointer. This may lead to object slicing and any kind of memory problem as a consequence. Try to use AbstractAlarmField& as the type of Device fields instead.
It is not useful to convert a member pointer X C::* to Y C::*. The Standard allows it as a reinterpret_cast or C-style cast, but with entirely unspecified results (unless you convert back to the original type). You would be better off using a virtual functor to safely get the AbstractAlarmField subobject:
#include <type_traits>
#include <memory>
struct AlarmGetter {
public:
virtual ~AlarmGetter();
virtual AbstractAlarmField& get(Device& dev) const = 0;
};
template <typename T>
struct AlarmMemberPtr
: public AlarmGetter {
static_assert(std::is_base_of<AbstractAlarmField, T>::value,
"Member type is not an AbstractAlarmField");
public:
explicit AlarmMemberPtr(T Device::*member)
: m_member( member ) {}
virtual AbstractAlarmField& get(Device& dev) const {
return dev.*m_member;
}
private:
T Device::*m_member;
};
template <typename T>
std::unique_ptr<AlarmGetter> make_alarm_getter(T Device::*member) {
std::unique_ptr<AlarmGetter> ptr(new AlarmMemberPtr<T>(member));
return ptr;
}
// To populate:
std::vector<std::unique_ptr<AlarmGetter>> alarmFieldCollection;
alarmFieldCollection.push_back(make_alarm_getter(&Device::hardwareMissingAlarm));
alarmFieldCollection.push_back(make_alarm_getter(&Device::hardwareErrorAlarm));
alarmFieldCollection.push_back(make_alarm_getter(&Device::badConfigAlarm));
// To use:
if (alarmFieldCollection[i]->get(*pDev).isRaised(pContext))
If it might be useful, you could also easily add an overload
virtual const AbstractAlarmField& get(const Device& dev) const;