Syntax to heap allocate anything? - d

Is there a syntax, template or function that allows me to essentially turn any value into a pointer to that value? I.e. copy it to the gc heap and return a pointer to it? "new" doesn't work for all types, std.experimental.allocator doesn't work in ctfe, and both seem to have troubles making pointers to delegates.

You can put the data in question inside a struct, then use the new keyword on that struct.
T* copy_to_heap(T)(T value) {
// create the struct with a value inside
struct S {
T value;
}
// new it and copy the value over to the new heap memory
S* s = new S;
s.value = value;
// return the pointer to the value
return &(s.value);
}
void main() {
// example use with a delegate:
auto dg = copy_to_heap(() { import std.stdio; writeln("test"); });
(*dg)();
}
That assumes you already have a value to copy but that's probably easier and the way you'd do it anyway. But you can also tweak the code to remove that requirement if you want (perhaps just pass typeof.init for example).

Related

Initialization of values before constructor

Problem:
I implemented this new opeator for my class.
void* Objects::MemoryObject::operator new(size_t size, Memory::BaseAllocator* allocator) {
Objects::MemoryObject* newObject = static_cast<Objects::MemoryObject*>(allocator->allocateItem(size));
newObject->_objectAllocator = allocator;
newObject->_objectSize = size;
return newObject;
}
It will allocate memory for object and set attributes for object size and allocator used in allocation. Problem is that these values will be removed by constructor (object size will be 0, pointer to allocator will be NULL) even if i don't initialize them in code. How to avoid this? Is there any way to tell compiler that these attributes are initialized before constructor ?
What i tried: I tried to use volatile qualifier but it doesn't work
I think, you shouldn't use ordinal new for your task. Use something like "fabric": specific function, it allocates memory, creates instance and fills additional values.
Only thing that works is adding one structure that is holding informations. These informations are used later by constructor. This struct is defined in code file (.cpp) so it is invisible for other objects in program.
// Here we will save our values
struct {
Memory::BaseAllocator* allocator;
Memory::SystemInt size;
} MemoryObjectValues;
// we will take values from struct save them in attributes
Objects::MemoryObject::MemoryObject() {
this->_objectAllocator = MemoryObjectValues.allocator;
this->_objectSize = MemoryObjectValues.size;
MemoryObjectValues.allocator = nullptr;
MemoryObjectValues.size = 0;
}
// during allocation we will save values into struct
void* Objects::MemoryObject::operator new(size_t size, Memory::BaseAllocator* allocator) {
Objects::MemoryObject* newObject = static_cast<Objects::MemoryObject*>(allocator->allocateItem(size));
// set important values like size and pointer to allocator
MemoryObjectValues.allocator = allocator;
MemoryObjectValues.size = size;
return newObject;
}

Create new struct, insert into list, re-use pointer, return in vector... whether and how to delete?

In C++ code that I wrote to demonstrate an algorithm in an answer, I'm creating structs in a function using new, storing them in a list, moving them to a vector, then returning the vector:
struct my_struct {int a, b, c;};
std::vector<my_struct> myFunction(...) {
std::list<my_struct> my_list;
std::list<my_struct>::iterator current = my_list.begin();
std::vector<my_struct> my_vector;
my_struct *new_struct = nullptr;
while (...) {
...
if (!new_struct) {
new_struct = new my_struct;
new_struct->a = ...
}
...
if (new_struct) {
new_struct->b = ...
my_list.insert(current, *my_struct);
my_struct = nullptr;
}
...
if (...) {
current->c = ...
my_vector.push_back(*current);
current = my_list.erase(current);
}
...
}
return my_vector;
}
It compiles and seems to work correctly, however I'm more used to JavaScript and this code just feels like translated JavaScript; I'm specifically wondering whether I'm creating memory leaks, and whether I have to delete the structs in the calling function (and how).
Yes, you have a memory leak. If you invoke the new command, you will need to invoke a delete command in the future to free the memory allocated by new.
So, in this statement:
my_list.insert(current, *my_struct);
you are indeed copy the contents of *my_struct, not getting the ownership of it. So, in the following statement:
my_struct = nullptr;
You just got a memory leak.
To solve this, change your design to use smartpointer, for example, unique_ptr, or, better yet, dont use pointer at all, and just use a plain object:
my_struct new_struct;
As others in the question section have already pointed out, you probably shouldn't use new at all. The only reason to use pointers there at all is the if(newstruct) checks, if they are an essential part of your algorithm.
But if you use new, you should delete, too. It's safe to do that after inserting the struct into the list or vector - the list and vector contain copies.
Beginning with C++17, std::optional (and before that, boost::optional) is a sensible alternative solution for your specific problem here. It removes the need for pointers and the danger of memory leaks but at the same time still gives you a "nothing" state.
Your pseudo code would become something like:
// this is the correct way of defining a struct in C++:
struct my_struct {
int a;
int b;
int c;
};
std::vector<my_struct> myFunction(...) {
std::list<my_struct> my_list;
std::list<my_struct>::iterator current = my_list.begin();
std::vector<my_struct> my_vector;
std::optional<my_struct> new_struct; // new_struct does not hold a value
while (...) {
...
if (!new_struct.has_value()) { // if it does not hold a value...
new_struct = my_struct(); // it holds a value now (a default my_struct)
new_struct->a = ... // access syntax like a pointer
}
...
if (new_struct.has_value()) {
new_struct->b = ...
my_list.insert(current, *new_struct); // dereference syntax like a pointer
new_struct.reset(); // it no longer holds a value now
}
...
if (...) {
current->c = ...
my_vector.push_back(*current);
current = my_list.erase(current);
}
...
}
return my_vector;
}
Note how the syntax of std::optional deliberately mimics that of pointers.

C++ , how come I do not get the value "123456"

I am trying to print out value 123456, but it gives me the garbage value. How can I fix it? And Can you please explain why it gives the wrong value?
#include <stdio.h>
#include <stdlib.h>
struct MyInfo
{
private:
int private_key = 123456;
public:
int setkey(int value)
{
private_key = value;
}
int GetScore()
{
return private_key;
}
};
void main()
{
MyInfo* pMyInfo;
pMyInfo = (MyInfo*)malloc(sizeof(MyInfo));
printf("%d\n", pMyInfo->GetScore());
free(pMyInfo);
}
Don't use malloc/free but rather pMyInfo = new MyInfo() and delete pMyInfo. Only new will call the constructor which initializes the value; only delete will call the destructor.
Regarding the comment, what is meant is, you can also have it on the stack, i.e. MyInfo pMyInfo;, i.e. not a pointer. That will automatically call the constructor and when it goes out of scope, the destructor.
int private_key = 123456;
This really is just a camouflaged constructor initialization which means it's the same as:
MyInfo() : private_key(123456) {}
Since malloc and friends are inherited from C and C has no classes (and thus no special member functions) whatsoever malloc and friends won't call these necessary special member functions to set up your object. The C++ equivalent new does however which is why you should always use new over malloc and delete over free.
But wait, there's more...
Actually, you shouldn't ever use new either, there are always better alternatives than using raw dynamic allocation. If you really need dynamic memory allocation then use std::unique_ptr or for multiple objects std::vector but most of the time you don't even need these ( there are tons of posts on here that explain when dynamic allocation is a must, for all the other cases just use storage with automatic lifetime) all you need in this case is a local object:
MyInfo myInfo;
printf("%d\n", myInfo.GetScore());
See how your code just got shorter, easier to maintain and cleaner to achieve the same?
When you declare a pointer of type MyInfo, it does not mean that the object it points to will actually be your struct, it just assumes it will be.
When you do malloc(sizeof(MyInfo)), you simply allocate memory of the size which your struct might take, it does not create an object. Hence, when you try to do GetScore(), it accesses memory location which it assumes contains your private_key, but instead it simply contains garbage.
Don't mix C and C++
You should avoid malloc/alloc etc in C++ and opt for new operator if you want to work with dynamically allocated objects.
Add a constructor to initialize the value
private;
int private_key;
public:
MyInfo () {
private_key = 123456;
}
And implement the main like
// without pointer
void main () {
MyInfo myinfo;
printf("%d\n", myinfo.GetScore());
}
// with pointer
void main () {
MyInfo *myinfo = new MyInfo();
printf("%d\n", myinfo->GetScore());
}
Just for reference, it is possible to initialize an object in raw storage, but it would be overkill and rather stupid for this use case. As malloc only allocate raw memory and does not construct an object, you could use a placement new to build the object in a second time:
int main() // I can't stand void main
{
MyInfo* pMyInfo;
pMyInfo = (MyInfo*)malloc(sizeof(MyInfo)); // only allocate raw memory
new((void *) pMyInfo) MyInfo; // construct the object
std::cout << pMyInfo->GetScore() << std::endl; // no reason for C printf here
pMyInfo->~MyInfo(); // placement new requires explicit destructor call if not trivial
free(pMyInfo);
return 0;
}
DO NOT DO THAT for such a simple case. Placement new should only be used in very special cases where the allocation is not trivial, for example when you use share memory. But here the correct way is to simply use an automatic object:
int main() // I can't stand void main
{
MyInfo pMyInfo;
std::cout << pMyInfo.GetScore() << std::endl;
return 0;
}

Using shared pointers with memory allocated in another function

I have some legacy-era code at work that takes in a double-pointer and allocates memory to it. A shortened example of it would look something like this:
struct LegacyObj
{
int a;
double b;
};
void LegacyAllocator(LegacyObj** ppObj)
{
*ppObj = (LegacyObj*)malloc(sizeof(LegacyObj));
}
void LegacyDeleter(LegacyObj** ppObj)
{
free(*ppObj);
}
The actual LegacyAllocator function is ~100 lines and mixes reading from files with creating a linked list of LegacyObj pointers, and isn't something I'd be able to get away with rewriting right now. I would like, however, to make the use of this function a bit safer, avoiding any memory leaks that may occur from exceptions &tc. The first solution I came up with was to wrap it up in a class and handle calling the legacy functions in the ctor/dtor.
class RAIIWrapper
{
public:
RAIIWrapper()
:obj{nullptr}
{
::LegacyAllocator(&obj);
}
RAIIWrapper(RAIIWrapper&& that)
: obj{ that.obj}
{
that.obj = nullptr;
}
RAIIWrapper& operator=(RAIIWrapper&& that)
{
RAIIWrapper copy{std::move(that)};
std::swap(obj, copy.obj);
return *this;
}
~RAIIWrapper ()
{
::LegacyDeleter(&obj);
}
private:
LegacyObj* obj;
};
But I'm curious - is there a way to do this using std::shared_ptr or std::unique_ptr? I've not been able to come up with a solution without having to keep the original pointer passed to LegacyAllocator around.
Yes, you can use a custom deleter with std::unique_ptr or std::shared_ptr, for example:
struct Deleter {
void operator()(LegacyObj *p) const {
LegacyDeleter(&p);
}
};
std::unique_ptr<LegacyObj, Deleter> MakeLegacyObj() {
LegacyObj *p = 0;
LegacyAllocator(&p);
return std::unique_ptr<LegacyObj, Deleter>(p);
}
std::unique_ptr<LegacyObj, Deleter> p = MakeLegacyObj();
And, as correctly pointed out by #Dave, this works with shared_ptr too:
std::shared_ptr<LegacyObj> p = MakeLegacyObj();
You can use unique_ptr to delete the memory, but you'll have to provide a custom Deleter class since the memory is allocated using malloc rather than new.
Better yet, change the allocation code to use new instead and just use unique_ptr. If you go down this road you can just have the allocator return a unique_ptr instead of a pointer to the memory.
Assuming you need to provide your own custom deleter, here is one way you might do it:
template <typename T>
class MallocDeleter
{
public:
void operator() (T* obj) const
{
LegacyDeleter (*obj);
}
};
typedef std::unique_ptr <LegacyObj, MallocDeleter <LegacyObj>> unique_legacy_ptr;
You could also probably provide a make_unique_legacy type function which allocates by calling LegacyAllocator, instead of having to initialize the unique_ptr yourself.
You can create a factory function for unique_ptrs like this:
typedef void(* LegacyDeleterType)(LegacyObj*);
typedef std::unique_ptr<LegacyObj,LegacyDeleterType> UniqueLegacyPtr;
UniqueLegacyPtr makeUniqueLegacyObj()
{
LegacyObj * p = nullptr;
LegacyAllocator( &p );
return UniqueLegacyPtr( p, [](LegacyObj*p){ LegacyDeleter(&p); } );
}
You can now use that to create unique_ptrs and you can also assign to shared_ptrs which capture the custom deleter automatically at construction:
int main()
{
auto unique = makeUniqueLegacyObj();
std::shared_ptr<LegacyObj> shared = makeUniqueLegacyObj();
}

Does the vector still exists?

I'm having a problem in my c++ game related with the vector.
I want to know if theres any code that tells me if a vector still exists.
Example (x = a structure that I created):
vector<x*> var;
var.push_back(new x);
var[5]->Pos_X = 10;
And now what i want:
delete var[5];
if(var[5] still exists){
var[5]->Pos_X = 20;
}
What could be the code for var[5] still exists?
Unless you've actually set the pointer to null after deleting it, there's no real way to determine whether that slot in the vector contains a pointer to a live object or not.
So you'd need to:
delete vec[5];
vec[5] = NULL;
Then you could test
if (vec[5] == NULL)
to determine if there was "really" something at that location or not.
There is no code for that, not without extra careful work in your deleting process. If you store smart pointers you can do it like this:
vector<unique_ptr<x>> var;
// assuming you actually do add 6 or more elements to the vector
...
var[5].reset();
if (var[5]) { ... }
You could use var.size() to see if the vector contains a pointer at var[5], but that won't tell you whether the pointer is valid.
You could create a small wrapper class:
template <class T>
class wrapper {
bool valid;
T *data_;
public:
wrapper(T *d): data_(d), valid(true) {}
del() { delete data; valid = false; }
bool isValid() { return valid; }
T *data() { return valid ? data : NULL; }
};
std::vector<wrapper<x> > var;
var[5].del();
if (var[5].valid())
var[5].data()->Pos_X = 20;
Personally, I'd prefer to just ensure that all the pointers are valid all the time though.
calling delete you are deallocating memory pointed by that x*, so you still have pointer to some memory address that do not contain anymore what you excpected.
If you want to remove elements from vector consider using "erase"; then, if you don't want to erase but simply "cancel" the Nth element, structure is yours.. put some bool flag inside your structure.