Cereal does not support raw pointers - c++

Edit: The question title was based on a deep missunderstanding of the compiler error I got. I was (sillyly) assuming the error was, that I tried to deserialize to an object I declared inside of the function. This was utterly wrong. I didn't do enough debug efforts myself or I could have found out what was wrong. So the title was quite missleading and I changed it. Thanks to Андрей Беньковский for helping.
I'm writing Serialization functions for 3D Models in my engine using cereal, which proves to be really efficient and easy to use.
So far everything worked great when I tested (de-)serializing a simple Mesh.
But now I'm trying to deserialize another class but ran in a problem I don't get.
void loadFile(std::string filepath)
{
DescriptionFile file;
{
ifstream stream = ifstream(filepath, std::ifstream::binary);
PortableBinaryInputArchive archive(stream);
archive(file);
stream.close();
}
}
This is my class, that should be deserialized:
struct DescriptionFile
{
public:
DescriptionFile(){}
map<string, MeshDescription*> meshDescriptions;
map<string, ModelDescription*> modelDescriptions;
public:
template<class Archive>
void serialize(Archive & archive)
{
archive(meshDescriptions, modelDescriptions);
}
};
It gives me compiler error:
Cereal does not support serializing raw pointers - please use a smart pointer
Even though it's not a pointer. In another part of the code something similar works just fine. I'd be glad if somebody could help me solve this.

I never used Cereal, but it looks like it expects you to use something like this:
map<string, unique_ptr<MeshDescription> >
To get std::unique_ptr I usually #include <memory>
From cereal documentation:
cereal supports serializing smart pointers but not dumb pointers (that is to say raw pointers, such as int *) or references. Pointer support can be found by including <cereal/types/memory.hpp>.
May be it means you have to include their header instead of the standard.
P.S. When your object owns resources (e.g. dynamically allocated MeshDescription) always delegate resource management (allocation, deallocation, copying, etc) to a separate class (smart pointer, collection, wrapper, etc). See rule of 0.

Related

How to handle memory management when passing pointers to library functions

I'm working on a project in C++/CLI currently, and I'm trying to wrap my brain around memory allocation. In my code I need to call methods from an external library that I don't have the ability to edit or read the source code. A specific issues I've ran into is the following. They have a class something like this:
class Item {
public:
void SetName(const char* name);
};
Nothing too unusual, it has a method for setting the name... but wait a minute... how am I supposed to free that char* pointer? If I call it from my code like this:
void MyMethod(Item* myItem){
char* name = CallOtherMethodThatGivesMeTheName();
myItem->SetName(name);
};
When am I supposed to deallocate name? I can't stay inside this function forever waiting until myItem no longer uses it, and I have absolutely no clue how the library has implemented SetName().
Should I just delete name within this scope? Won't that mean myItem no longer has a valid pointer though? Maybe I should use some sort of smart pointer? In general, is there a standard way to handle this situation?
And since I am using C++ / CLI, my actual method looks like the following, but I'm looking for a general solution (this might be wrong too).
void MyMethod(Item* myItem, String^ name){
pin_ptr<const wchar_t> pinned_name = PtrToStringChars(name)
myItem->SetName(pinned_name);
};
Thanks for any help!
Ignoring the CLI portion of your question, I provide the following answer. I don't think using CLI is relevant to the core of your question. What you really want to know is when the third party library deems it safe for you to release some allocated string you passed it.
Given the code you provided:
class Item {
public:
void SetName(const char* name);
};
and assuming there is no documentation, I would assume the library makes an internal copy of a c-style string that you provide and that there is no reason to concern yourself with freeing it any more than you would normally. I make this assumption from the context. That would be the proper thing to do. Granted not all third party libraries do the "proper thing", but you cannot be omnipotent.
For example, I would assume:
#include <string>
int main()
{
Item item;
{
std::string name("Sam");
item.SetName(name.c_str());
}
// Carry on doing things with item...
return 0;
}
works just fine, until I examine some behavior that says otherwise. If I am concerned about a third party library behaving poorly, then I test the above in a loop and watch the memory, or witness access violations, but not until I have reason to do so.
In the end:
) Read the documentation for the library.
) Ask on their user groups or forums.
) If none is available, use intuition and context.
) If something unexpected happens, then test.
When you change the value of name after you called SetName and the library uses the originally provided value you know it has been copied.
Otherwise it uses always the current pointer and you cannot deallocate it safely due to the fact you don't know in which order the compiler releases the objects when the program ends.
Usually you only "delete" what you create with "new".
Libraries that return data with pointers, work in two way:
1- Ask you to allocate memory and pass them the pointer (datatype * p)
2- Allocate for you and give you the pointer (return datatype *) or (argument datatype ** p) or (argument datatype * & p)
In first way you know when to free your memory.
In second way, when you finished working with data, you need to call another function from the same library to free the memory for you, pair functions like this pattern are quite common (open close) (alloc free) ...
Of course there can be other ways, so always reading documentation is the best.
In C++/CLI you don't delete objects defined with "^" sign, garbage-collector will take care of them.

boost serialization of pointer to primitive without wrapper

Is there any way to serialize a pointer to a primitive without wrapping it in a class?
I notice a comment on the following question that it would require tracking all primitives of that type in the program, which I guess could slow down serialization somewhat. But what if I'm ok with that? Is there a way to enable tracking for all primitive types?
How do I serialize a class containing pointers to primitives?
I found this thread (from 2006) which also alludes to the problem. It seems that serializing a pointer to primitive should be possible, but the lack of tracking makes it something that you probably would not want. It seems to allude to the possibility but does not explain if it was ever implemented.
http://boost.2283326.n4.nabble.com/serialization-serialization-of-pointers-to-primitive-types-td2561086.html
you can write a overload function for operator&,like this:
template<class Archive>
void operator&(Archive & ar, const char* &p)
{
}

What vb6 type is ABI-compatible with std::vector?

I've been writing a DLL in C++, now I must call this DLL from a VB6 application.
Here's a code sample from this DLL :
#include <vector>
#include <string>
using namespace std;
void __stdcall DLLFunction (vector<Object>*)
{
// performs a few operations on the Objects contained in the vector.
}
struct Object
{
long CoordX;
long CoordY;
long Width;
long Height;
LPSTR Id;
};
I also defined the "Object struct" in VB6
Private Type Object
CoordX As Integer
CoordY As Integer
Width As Integer
Height As Integer
Id As String
End Type
The issue is I don't know what vb6 type could stand for std::vector in order to call the DLL's function.
Notes :
- I use a vector for the DLL to be able to add objects.
- I use a pointer in order to use as less memory as possible.
- Sorry for my english, it ain't my home language at all.
- Thank you for reading and trying to help me.
Edit :
- I fixed the typing issues (Ids are definitely ended by NullChar, so LPSTR should do the trick).
- I read your answers, and I'd like to thank both of you, your answers are close to one another and a major issue remains. My DLL definitely needs to add elements to the container. Thus, I'm wondering how I could do the trick. Maybe I could add a return type to my function and then make that the function is able to return the items it created (instead of putting it directly into the container) so that the vb6 application gets these items and is able to process them, but I can't figure out how to do this
Edit bis :
#Rook : I feel like I could achieve this by using a new struct.
struct ObjectArrayPointer
{
Object* Pointer;
size_t Counter;
}
And then call my function this way :
void __stdcall DLLFunction (ObjectArrayPointer*);
I would then be able to add objects and edit the size parameter for my VB6 application to find these new objects. Was that what you meant?
You should not be trying to export template containers from a DLL anyway. They're likely to break when faced with newer compilers and libraries (eg. a library built under C++03 will not play well with code built using C++11).
The least painful thing to do is to accept a pointer to a buffer and a length parameter,
void __stdcall DLLFunction (Object* buffer, size_t nObjects);
if the size of the container will not change during execution. This interface is about as simple as it gets, and is easily accessible by any language that understand C calling conventions (eg. almost every single one.)
You've already thrown away most of the use of a std::vector because you've already specialised it to Object; you could consider going all the way and creating your own ObjectCollection class which uses a std::vector internally but presents a non-templated interface. Here's a simple example :
// In your public API header file:
typedef struct object_collection_t *object_collection;
object_collection CreateObjectCollection();
void DestroyObjectCollect(object_collection collection);
void AddObjectToCollection(object_collection collection, Object* object);
// etc
No template types are exposed in any form in the header. This is good.
// And the corresponding code file:
struct object_collection_t
{
std::vector<Object*> objects;
};
object_collection CreateObjectCollection() { return new object_collection_t; }
void DestroyObjectCollect(object_collection collection) { delete collection; }
void AddObjectToCollection(object_collection collection, Object* object)
{
collection->objects.push_back(object);
}
// etc
All of templating code is hidden away, leaving you with a fairly clean and simple interface which present an opaque pointer type that can be passed around by external code but only queried and modified by your own, etc.
EDIT: Incidentally, I've used Object* throughout the above code. It may well be safer and impler to use just plain old Object and avoid all of the issues associated with memory management and pointer manipulation by client code. If Object is sufficiently small and simple, passing by value may be a better approach.
(NB: not checked for compilability or functionality. E&OE. Caveat Implementor!)
You can't do that as it's a C++ class/template. Internally, it's an array but not in a way that can be created from VB6.
Your best bet is to change the function to accept a pointer to an array with a count parameter.
You'll also need to be very careful as to how the type is structured.
C++ ints are Longs in VB6.
Also, the Id string won't be compatible. VB6 will have a pointer to a unicode BString (unless you make it fixed length) where as a C++ will have std::string which is an array of ANSI chars. VB6 MAY marshal this if you pass an array of the objects (rather than a pointer)
The VB6 ABI is the COM Automation ABI.
Therefore, if you need an arry which is VB6 ABI compatible, you should probably use SAFEARRAY. I suggest you should also be using the Compiler COM Support classes:
http://msdn.microsoft.com/en-US/library/5yb2sfxk(v=vs.80).aspx
This question appears to do exactly what you want, using ATL's CComSafeArray class:
conversion between std::vector and _variant_t
You may also want to look at these:
https://stackoverflow.com/search?q=safearray+_variant_t
Alternatives to SAFEARRAY
The alternative to SAFEARRAY is to supply a COM Collection object. This is simply a COM object with a Dispinterface or Dual interface with the methods Count and Item. Item should have dispid=0 to be the default method. You may also want to supply _NewEnum with DISPID_NEWENUM to support the For Each syntax.

Dynamic array of objects in C++

I'm trying to create a dynamic array of objects, similar to ArrayLists in Java. I'm new at C++ and can't get it to work.
class Album{
private:
public:
void addPhoto(Photo p){
}
};
What should my private datamember look like and how do I add p to it? And do I need a pointer for some reason?
The functionality you look for already exits in the stl collection classes and and with out knowing you application it would be had to tell you weather you needed a pointer or not.
The basic layout of you underlying container could be something like this.
class Album{
public:
void addPhoto(Photo p){
Photos.push_back(p);
}
private:
std::vector<Photo> Photos;
};
You should use an std::vector.
You could use the built in std::vector class that behaves very similarly to the ArrayList. (edit... looks like someone beat me to it)
#fontanini gave you a good answer, you should use vector if you need a dynamic array of objects.
But maybe you don't need a class to begin with. Not everything in C++ needs to be encapsulated in a class, unless you really need it.
Think about your data structure and what are the requirements. You might want to learn more about standard C++ library and the STL to familiarize yourself with other containers and their capabilities, limitations and objectives:
There are excellent video lectures on STL "Introduction to STL with Stephan T Lavavej"

Best way to take a snapshot of an object to a file

What's the best way to output the public contents of an object to a human-readable file? I'm looking for a way to do this that would not require me to know of all the members of the class, but rather use the compiler to tell me what members exist, and what their names are. There have to be macros or something like that, right?
Contrived example:
class Container
{
public:
Container::Container() {/*initialize members*/};
int stuff;
int otherStuff;
};
Container myCollection;
I would like to be able to do something to see output along the lines of "myCollection: stuff = value, otherStuff = value".
But then if another member is added to Container,
class Container
{
public:
Container::Container() {/*initialize members*/};
int stuff;
string evenMoreStuff;
int otherStuff;
};
Container myCollection;
This time, the output of this snapshot would be "myCollection: stuff = value, evenMoreStuff=value, otherStuff = value"
Is there a macro that would help me accomplish this? Is this even possible? (Also, I can't modify the Container class.)
Another note: I'm most interested about a potential macros in VS, but other solutions are welcome too.
What you're looking for is "[reflection](http://en.wikipedia.org/wiki/Reflection_(computer_science)#C.2B.2B)".
I found two promising links with a Google search for "C++ reflection":
http://www.garret.ru/cppreflection/docs/reflect.html
http://seal-reflex.web.cern.ch/seal-reflex/index.html
Boost has a serialization library that can serialize into text files. You will, however, not be able to get around with now knowing what members the class contains. You would need reflection, which C++ does not have.
Take a look at this library .
What you need is object serialization or object marshalling. A recurrent thema in stackoverflow.
I'd highly recommend taking a look at Google's Protocol Buffers.
There's unfortunately no macro that can do this for you. What you're looking for is a reflective type library. These can vary from fairly simple to home-rolled monstrosities that have no place in a work environment.
There's no real simple way of doing this, and though you may be tempted to simply dump the memory at an address like so:
char *buffer = new char[sizeof(Container)];
memcpy(buffer, containerInstance, sizeof(Container));
I'd really suggest against it unless all you have are simple types.
If you want something really simple but not complete, I'd suggest writing your own
printOn(ostream &) member method.
XDR is one way to do this in a platform independent way.