I want to find a way to encapsulate a header-only 3rd party library without exposing its header files. In our other projects, we encapsulate by using void*: in the implementation, we allocate memory and assign to it, and cast to pointer of its original type when we use it. But this time, the encapsulated class is used frequently, hence dynamic allocation is unacceptable. Here is another solution I'm currently considering.
Assuming that the encapsulated class need N bytes, I will make a char array member variable of size N in the wrapper class, named data, for instance. In the implementation, when I try to assign an object of the encapsulated class to the wrapper, or forward a function call, I need to cast &data to the pointer of encapsulated class by reinterpret_cast, firstly. The char array is completely a placeholder. To make this clear, here is a sample code.
#include <iostream>
struct Inner {
void print() const {
std::cout << "Inner::print()\n";
}
};
struct Wrapper;
Inner* addressof(Wrapper&);
const Inner* addressof(const Wrapper&);
struct Wrapper {
Wrapper() {
Inner* ptr = addressof(*this);
*ptr = Inner();
}
void run() const {
addressof(*this)->print();
}
char data[1];
};
Inner* addressof(Wrapper& w) {
return reinterpret_cast<Inner*>(&(w.data));
}
const Inner* addressof(const Wrapper& w) {
return reinterpret_cast<const Inner*>(&(w.data));
}
int main() {
Wrapper wrp;
wrp.run();
}
From the view of memory, this seems make sense. But I'm sure if this is some kind of undefined behaviour.
Additionally, I want to know if there is a list of undefined behaviour. Seems like cppreference doesn't contain such thing and C++ standard specfication is really hard to understand.
What you have here is undefined behavior. The reason is when you reinterpret an object to a different type, you are not allowed to modify it until you cast it back to the original type.
In your code, you originally have the data as a char[1]. Later, in your constructor, you reinterpret_cast &data as Inner*. At this point, modifying the its value will produce undefined behavior.
What you could do however, is to first create a Inner object, then cast it and store it in the char[1]. Later you can cast the char[1] back to the Inner object and do anything with the Inner object as wanted.
So now your constructor would look like this:
Wrapper() {
Inner inner;
char* ptr = reinterpret_cast<char*>(&inner);
std::memcpy(data, ptr, 1);
}
However, if you did it like this, then you don't even need the reinterpret_cast there as you can directly memcpy from inner:
Wrapper() {
Inner inner;
std::memcpy(data, &inner, 1);
}
Better, if you have C++20, then you can and should use std::bit_cast, along with std::byte(C++17) and std::array(C++11):
struct Wrapper {
Wrapper()
: data(std::bit_cast<decltype(data)>(Inner{}))
{}
void run() const {
std::bit_cast<Inner>(data).print();
}
std::array<std::byte, 1> data;
};
Demo: https://godbolt.org/z/MaT5sasaT
Related
I have the following code which seems to work always (msvc, gcc and clang).
But I'm not sure if it is really legal. In my framework my classes may have "two constructors" - one normal C++ constructor which does simple member initialization and an additional member function "Ctor" which executes additional initialization code. It is used to allow for example calls to virtual functions. These calls are handled by a generic allocation/construction function - something like "make_shared".
The code:
#include <iostream>
class Foo
{
public:
constexpr Foo() : someConstField(){}
public:
inline void Ctor(int i)
{
//use Ctor as real constructor to allow for example calls to virtual functions
const_cast<int&>(this->someConstField) = i;
}
public:
const int someConstField;
};
int main()
{
//done by a generic allocation function
Foo f;
f.Ctor(12); //after this call someConstField is really const!
//
std::cout << f.someConstField;
}
Modifying const memory is undefined behaviour. Here that int has already been allocated in const memory by the default constructor.
Honestly I am not sure why you want to do this in the first place. If you want to be able to initalise Foo with an int just create an overloaded constructor:
...
constexpr Foo(int i) : someConstField{i} {}
This is completely legal, you are initalising the const memory when it is created and all is good.
If for some reason you want to have your object initalised in two stages (which without a factory function is not a good idea) then you cannot, and should not, use a const member variable. After all, if it could change after the object was created then it would no longer be const.
As a general rule of thumb you shouldn't have const member variables since it causes lots of problems with, for example, moving an object.
When I say "const memory" here, what I mean is const qualified memory by the rules of the language. So while the memory itself may or may not be writable at the machine level, it really doesn't matter since the compiler will do whatever it likes (generally it just ignores any writes to that memory but this is UB so it could do literally anything).
No.
It is undefined behaviour to modify a const value. The const_cast itself is fine, it's the modification that's the problem.
According to 7.1.6.1 in C++17 standard
Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const
object during its lifetime (3.8) results in undefined behavior.
And there is an example (similar to yours, except not for class member):
const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq); // cast required
*iq = 4; // undefined: modifies a const object
If your allocation function allocates raw memory, you can use placement new to construct an object at that memory location. With this you must remember to call the destructor of the object before freeing the allocation.
Small example using malloc:
class Foo
{
public:
constexpr Foo(int i) : someConstField(i){}
public:
const int someConstField;
};
int main()
{
void *raw_memory = std::malloc(sizeof(Foo));
Foo *foo = new (raw_memory) Foo{3}; // foo->someConstField == 3
// ...
foo->~Foo();
std::free(foo);
}
I suggest, that you use the constructor to avoid the const cast. You commented, that after your call of Ctor the value of someConstField will remain const. Just set it in the constructor and you will have no problems and your code becomes more readable.
#include <iostream>
class Foo
{
public:
constexpr Foo(int i) : someConstField(Ctor(i)){}
int Ctor(); // to be defined in the implementation
const int someConstField;
};
int main()
{
Foo f(12);
std::cout << f.someConstField;
}
I have a class in which I would like one of the functions to pass a unique ptr object to a char array. But I'm confused on several on features of unique pointers. I'm aware a destructor is called automatically when there are no more references to the object but is still the same for primitive variables? For instance if I do this, will the memory be deleted?
class A {
private:
public:
A(std::unique_ptr<char[]> data) {
data = nullptr;
}
~A();
};
int main() {
auto data = std::make_unique<char[]>(10);
A a(std::move(data));
return 0;
}
The next question I have is: If I have a private object which I want to point to data, why does this result in a compiler error?
class A {
private:
std::unique_ptr<char[]> internaldata;
public:
A(std::unique_ptr<char[]> data) {
internaldata = data;
}
~A() {
internaldata = nullptr;
}
};
int main() {
auto data = std::make_unique<char[]>(10);
A a(std::move(data));
return 0;
}
However when I call std::move while assigning it, the code compiles fine.
class A {
private:
std::unique_ptr<char[]> internaldata;
public:
A(std::unique_ptr<char[]> data) {
internaldata = std::move(data);
}
~A() {
internaldata = nullptr;
}
};
int main() {
auto data = std::make_unique<char[]>(10);
A a(std::move(data));
return 0;
}
But why do I have to call std::move twice here? Once for passing the argument then the second for assigning? And what exactly occurs in terms of reference count during that process, does a reallocation, copy and deletion occur?
And finally, is it possible to pass data into the smart pointer during the deceleration? Because currently I do it like this:
auto data = std::make_unique<char[]>(10);
char* buf = data.get();
strcpy(buf, "hello\0");
But is it possible to do something along the lines of:
char hellobuffer[] = "hello";
auto data = std::make_unique<char[]>(hellobuffer);
Where data is automatically assigned the correct size needed to store hellobuffer and copies over the data itself?
I'm aware a destructor is called automatically when there are no more references to the object but is still the same for primitive variables?
The destructor is always logically called. However, since things like int and char are trivially-destructible, the compiler understands that nothing should actually get called.
For instance if I do this, will the memory be deleted?
Yes -- the whole point of std::unique_ptr<T> is that your memory is taken care of automatically.
A(std::unique_ptr<char[]> data) {
internaldata = data;
}
That example fails to compile because internaldata = data is calling the copy-assignment operator and copying std::unique_ptr instances is disallowed (hence the unique bit).
And what exactly occurs in terms of reference count during that process, does a reallocation, copy and deletion occur?
There is no reference count -- a std::unique_ptr either refers to something or it is empty. When you std::move from a std::unique_ptr, the moved-from variable becomes empty. If you are looking for a reference-counted pointer type, see std::shared_ptr<T>.
And finally, is it possible to pass data into the smart pointer during the deceleration?
No. For std::make_unique<T[]>, you are only allowed to pass a std::size_t (see overload 2). It should be easy to write a wrapper function for what you are looking for.
Consider the following code snippet:
class A
{
public:
void nonConstFun()
{
}
};
class B
{
private:
A a_;
A * pA_;
public:
void fun() const
{
pA_->nonConstFun();
//a_.nonConstFun(); // Gives const related error
}
};
int main()
{
B b;
b.fun();
}
Here I am expecting the compiler to fail the compilation for lack of constness for calling A::nonConstFun() inside B::fun() irrespective of the type of A object.
However the compiler complains for the object, but not for the pointer. Why?
I am using VS2017 on Windows 10.
The other answers explain the T* const vs T const * which is what is happening. But it is important to understand the implication of this beyond just the mere syntax.
When you have a T* inside a structure the pointer is inside the object (part of the layout of the objet), but the pointed object is physically outside of the structure. That is why a const object with a T* member is not allowed to modify the pointer, but it is allowed to modify the pointed object - because physically the pointed object is outside the enclosing object.
And it is up to the programmer to decide if the pointed object is logically part of the enclosing object (and as such should share constness with the enclosing) or if it is logically an external entity. Examples of former include std::vector, std::string. Examples of the latter include std::span, std::unique_ptr, std::shared_ptr. As you can see both designs are usefull.
The shortcoming of C++ is that it doesn't offer an easy way to express a logical constness as stated above (what you actually expected from your code).
This is known and for this exact purpose there is an experimental class which is not yet standard propagate_const
std::experimental::propagate_const is a const-propagating wrapper for
pointers and pointer-like objects. It treats the wrapped pointer as a
pointer to const when accessed through a const access path, hence the
name.
struct B
{
A a_;
std::experimental::propagate_const<A *> pA_;
void fun()
{
pA_->nonConstFun(); // OK
}
void fun() const
{
// pA_->nonConstFun(); // compilation error
}
};
It is enforced.
If you try changing the pointer, the compiler will not let you.
The thing that the pointer points to, however, is a different conversation.
Remember, T* const and T const* are not the same thing!
You can protect that by either actually making it A const*, or simply by writing your function in the manner that is appropriate.
I have an assignment where I have to use a linked list of node with void* as the data. I would be filling the nodes with an object. I want to know some way of accessing the members of the object after it is in the linked list, other than casting it to the class. Is it possible? Also, here's a chunk of my code just in case it helps clarify my question.
struct Node
{
void* data_;
Node* next_;
Node()
{
data_ = 0;
next_ = 0;
}
};
class Star
{
private:
char name_[ENTRY_SZ];
long temperature_;
double luminosity_;
double mass_;
double radius_;
public:
static char filePath_[ENTRY_SZ];
Star(char* name);
void SetTemperature(char* temp);
void SetLuminosity(char* lum);
void SetMass(char* mass);
void SetRadius(char* rad);
void PrintToConsole();
void AppendToFile();
};
I want to be able to call the PrintToConsole function after it is in a void*.
You cannot work with the pointee of a void* without first casting it first. If it points at a Star, for example, you could do something like this:
static_cast<Star*>(data_)->PrintToConsole(); // Haha, Star star!
That said, in C++, it's pretty unusual to store things like this. You're much better off using a template class so that you get back the type information you need.
No. You have to cast it to the appropriate object.
I would question the reason on using void pointers.
I would also suggest a dynamic cast might be better
You should cast it to the class. But if you really don't want to, you can use the offsetof macro:
The macro offsetof expands to a constant of type std::size_t, the
value of which is the offset, in bytes, from the beginning of an
object of specified type to its specified member, including padding if
any.
If type is not a standard layout type, the behavior is undefined.
If member is a static member or a member function, the behavior is
undefined.
But you should just cast it to the class.
EDIT: Ah, I see you want to access a method of the class. That's not possible. You should cast it to the class.
Since this is an assignment, you might be best to ask your teacher/mentor as to what their intents are for using a void* type in C++; void* types are not inherently bad, but there other ways of achieving similar results while maintaining language consistency.
To answer directly:
I want to know some way of accessing the members of the object after it is in the linked list, other than casting it to the class. Is it possible?
Yes it is possible, but not using the void* idiom. Using your code as an example, you would indeed have to cast to the appropriate type and be certain the types pointed to are compatible if you keep the void*, example:
struct Node
{
void* data_;
Node* next_;
Node()
{
data_ = 0;
next_ = 0;
}
};
class Star
{
public:
void PrintToConsole() {} // empty to avoid not-defined errors
};
int main() {
Node n;
n.data_ = new int(42);
static_cast<Star*>(n.data_)->PrintToConsole(); // this will compile fine, but what happens here is undefined
delete static_cast<int*>(n.data_); // can't delete void*, have to cast
return 0;
}
Again, since this is an assignment, your professor is probably just trying to teach about pointers and casting or the type system and you probably haven't learned about C++ templates, but since you asked, here's your code using templates:
template < typename T >
struct Node
{
T data_;
Node* next_;
// use member init list to construct default T object
Node() : data_(), next_(0)
{
}
};
class Star
{
public:
void PrintToConsole() {} // empty to avoid not-defined errors
};
int main() {
Node<Star*> n;
n.data_ = new Star();
n.data_->PrintToConsole(); // OK
delete n.data_; // no cast needed since data_ is a Star* type
Node<int*> n2;
n2.data_ = new Star(); // compiler error (data_ is of type int* not Star*)
n2.data_->PrintToConsole(); // compiler error (int has no member named PrintToConsole)
delete n.data_;
return 0;
}
This is just a simple example to illustrate what you were asking and it's still probably best to ask your teacher for more clarification if your confused on the topic.
Hope that can help.
I had a problem while hacking a bigger project so I made a simpel test case. If I'm not omitting something, my test code works fine, but maybe it works accidentally so I wanted to show it to you and ask if there are any pitfalls in this approach.
I have an OutObj which has a member variable (pointer) InObj. InObj has a member function. I send the address of this member variable object (InObj) to a callback function as void*. The type of this object never changes so inside the callback I recast to its original type and call the aFunc member function in it. In this exampel it works as expected, but in the project I'm working on it doesn't. So I might be omitting something or maybe there is a pitfall here and this works accidentally. Any comments? Thanks a lot in advance.
(The problem I have in my original code is that InObj.data is garbage).
#include <stdio.h>
class InObj
{
public:
int data;
InObj(int argData);
void aFunc()
{
printf("Inside aFunc! data is: %d\n", data);
};
};
InObj::InObj(int argData)
{
data = argData;
}
class OutObj
{
public:
InObj* objPtr;
OutObj(int data);
~OutObj();
};
OutObj::OutObj(int data)
{
objPtr = new InObj(data);
}
OutObj::~OutObj()
{
delete objPtr;
}
void callback(void* context)
{
((InObj*)context)->aFunc();
}
int main ()
{
OutObj a(42);
callback((void*)a.objPtr);
}
Yes, this is safe.
A pointer to any type can be converted to a pointer to void and back again.
Note that the conversion to void* is implicit, so you don't need the cast.
What you have posted should be "safe" insofar as a non type safe operation like this can be safe. I would replace the casts you have though with static_cast instead of C style casts, because static_cast doesn't allow you to make such unsafe conversions between types. If you try to do something unsafe with static_cast the compiler will tell you instead of leaving you guessing.
(Side unrelated note: InObj's constructor should use initialization rather than assignment:
InObj::InObj(int argData) : data(argData)
{
}
)