Release and cast data of a unique_ptr to another without copying - c++

I have a unique_ptr of an array of floats that I would like to change to a unique_ptr of an array of uint8_t in my function. In other words, unique_ptr<float[]> --> unique_ptr<uint8_t[]>.
This is what I have tried
void my_function(std::unique_ptr<float*> data) {
std::unique_ptr<uint8_t*> converted_data(reinterpret_cast<uint8_t*>(data.release()));
// ...
// Processing converted_data ...
}
Since I am getting this error: no matching constructor for initialization of 'std::unique_ptr<uint8_t *>', I was wondering if it is possible to achieve this goal without copying the data.

You are casting to an incompatible type.
data.release() is of type float** since it returns a raw pointer to whatever was in the unique_ptr (float* in this case). You should cast to uint_8t** instead ( though it still looks like a bad idea).

Related

How do I copy a C-style array into a void pointer in C++?

So basically I've recently started coding in C++ instead of C so maybe that's not the C++ way of doing this, but I've got a program where the user passes an array as a function parameter (void foo(void* pass_array_here)) and I want to copy it in a private member of a class, also declared as void* array_private. I'm copying it like this:
void foo(void* pass_array_here) {
array_private = pass_array_here;
}
I must note that I'm working with OpenGL so I don't know if I can rely on the new keyword or the heap in general. So how do I do that?
(Note, on a sizeof call, a 9-element float array appeared as 8 bytes in the stack, so it definitely didn't work).
As already commented above, using void* is not very useful.
If you need an array object, it's recommended in C++ to use either std::array for a fixed size array, or std::vector for dynamic size array.
This line: array_private = pass_array_here is simply assigning the pointer, not copying the array content.
If you use std::array or std::vector as suggested in point 2 above, you can utilize the copy constructor of these classes to actually copy the array's content easily:
void foo(std::vector<SomeType> const & pass_array_here) {
array_private = pass_array_here;
}
If the caller of the function foo does not need to use the array after calling the function, you can save the copy of the data, and utilize C++ move semantics (available since C++ 11):
void foo(std::vector<SomeType> && pass_array_here) {
array_private = std::move(pass_array_here);
}
If the caller does not have a std::vector but an old C style array, it is possible to initialize the std::vector member from it (which will copy the data). See: std::vector::assign.
For 4, 5 and 6 above, your private data member will have to be defined as:
std::vector<SomeType> array_private;
If you need to access the data buffer managed by an std::vector, you can use std::vector::data: std::vector::data. You can cast this data pointer into a void* if you need to pass it to a C style function, e.g. in opengl (no need to copy the data).
More about move semantics and R value references here: Understanding rvalue references

How push_back unique_ptr parameter onto vector of shared ptrs

I'm having a tough time pushing back a unique_ptr from my method parameter onto a vector of shared pointers.
IFCCB.h:
private:
vector<shared_ptr<IFC>> m_shpVectorIFC;
public:
void addElementVectorIFC(unique_ptr<IFC> rupIFC);
IFCCB.cpp:
void IFCCB::addElementVectorIFC(unique_ptr<IFC> rupIFC)
{
m_shpVectorIFC.push_back(std::unique_ptr<IFC>(new IFContent(rupIFC)));
}
I'm getting the error:
C2664: 'IFC::IFC(const IFC &)' : cannot convert argument 1 from
'std::unique_ptr>' to 'IFO *'
In this case, IFO is the heirarchical parent of IFC. I'm not sure why it's looking at that.
I've looked at vector info and shared_ptr info, as well as using unique_ptr with standard library containers.
Any ideas? I'm not used to working with shared_ptrs and unique_ptrs.
The problem is that push_back takes the container's value_type, which is shared_ptr<IFC>, but you are passing it a unique_ptr<IFC> and the conversion from unique_ptr to shared_ptr uses an explicit constructor and can only be done from a unique_ptr rvalue, so the argument cannot be implicitly converted to shared_ptr.
To make it work you need to use std::move to convert the unique_ptr to an rvalue and then either do the conversion to shared_ptr explicitly:
unique_ptr<IFC> p;
// ...
m_shpVectorIFC.push_back(std::shared_ptr<IFC>(std::move(p)));
Or use emplace_back instead, because that function can use explicit constructors to construct the new container element:
m_shpVectorIFC.emplace_back(std::move(p)));
I'm not convinced your code that creates a new unique_ptr is correct (why can't you just insert rupIFC into the container using either of the solutions shown above?) but if that's really what you want to do, the error you get is because you are trying to pass unique_ptr<IFC> to the IFContent constructor, which takes a IFO* not a unique_ptr<IFC>. To make that compile you need to get the raw pointer out of rupIFC:
std::unique_ptr<IFC>(new IFContent(rupIFC.get()))
However this is probably unsafe, because the pointer you passed to the IFContent constructor will be deleted at the end of the function when rupIFC is destroyed, so maybe you meant to release it:
std::unique_ptr<IFC>(new IFContent(rupIFC.release()))
N.B. as dlf's answer says, there is no point creating a unique_ptr if you just want to convert it to a shared_ptr immediately, so you could simply do:
m_shpVectorIFC.emplace_back(std::make_shared<IFContent>(rupIFC.release()));
Based on your addendum, you will need to use unique_ptr::get() to provide the IFContent constructor with the raw pointer it wants. Depending on what it does with that pointer, you may actually need to use release instead to prevent double-deletion. Also, no need to create an intermediate unique_ptr when it's just going to be converted right into a shared_ptr anyway:
void IFCCB::addElementVectorIFC(unique_ptr<IFC> rupIFC)
{
m_shpVectorIFC.push_back(std::shared_ptr<IFC>(new IFContent(rupIFC.get())));
}

handling memory for IDL sequence return types

I have an idl definition as follow
typedef sequence<octet> ByteArray;
interface Connection {
ByteArray get_id ();
}
And there is this client side code
ByteArray * idToEncrypt = connection->get_id();
encryptId(idToEncrypt);
... // rest of code
The function encryptId() has the signature ByteArray* encryptId(ByteArray* idToEncrypt). I cannot change this signature.
For automatic memory handling, the type of idToEncrypt was changed to ByteArray_var. The problem is I dont know how to get 'ByteArray *' from ByteArray_var and pass it to encryptId().
Is there a way to automatically handle memory allocated "idToEncrypt" and still pass it to encryptId() as "ByteArray *"?
You should look at the _var C++ mapping in the CORBA specs.
For a sequence type var, I think the best approach might be to use the inout() member, i.e.:
ByteArray_var idToEncrypt = connection->get_id();
encryptId(&idToEncrypt.inout());
inout returns a non-const reference and you're just taking the address of the underlying object with &.
Do note: inout does dereference the internal pointer, so it would be illegal to call inout() on a _var that doesn't hold a pointer. However, the call to get_id() must always return a valid pointer, so the code is OK without checking.
If you need a generic approach where you don't know if the _varis initialized, you could use:
ByteArray* p = idToEncrypt.operator->();
as operator-> seems to be the only way to directly get at the pointer.

Are pointers used when copying a class with huge array member?

I have a class storing an multidimensional array as member.
struct Structure
{
Structure()
{
memset(Data, 0, sizeof Data);
}
int Number;
int Data[32][32][32];
}
When I write a function returning an object of this Structure, are all the bytes if the Data member copied or is just a reference passed?
Structure Create(int Parameter)
{
Structure structure;
// modify structure based on parameter
// ...
return structure;
}
If that results in copying the whole block of data, how can I do better? And what would it change to allocate the object on the heap like Structure *structure = new Structure(); and returning that pointer?
When you return the object by value, the actual data (323 ints) will be copied. It's possible the compiler will optimise away the copy (so called "copy elision"), but that is never guaranteed.
If you allocate the object dynamically and return a pointer to it, there will be no copying, of course. If you have access to C++11, consider returning a std::unique_ptr, so that ownership is clear and there's no chance of memory leaks.
In C++11, you could also "do better" by turning the member Data into a conainer (such as std::vector) which internally stores its data on the heap and has move semantics. This means that when returning from a function, the container will be moved instead of copied, and data will not be duplicated.
When you return an object by value the object will not actually be copied, instead your function will populate the object directly in the callers memory. It's as if you did the following:
Structure s;
Create(Parameter, &s);
Although a little better as the default constructor doesn't even get called. This is called "return value optimisation". Although it's not guarenteed by the standard, it is performed by all mainstream C++ compilers (clang, gcc, and Visual C++ all included).
If you want it on the heap then do this:
Structure * Create(int Parameter)
{
Structure * structure = new Structure();
return structure;
}
But it's better to use a smart pointer. If you're using c++11 you can use std::unique_ptr.
std::unique_ptr<Structure> Create(int Parameter)
{
auto structure = std::unique_ptr<Structure>(new Structure());
return structure;
}
You can have it behave however you want. If you define a function like this...
Structure* someFunction();
will return a pointer to a Structure object. This object must be allocated with new. For example defining the function like this:
Structure* someFunction() {
Structure* someNewStructure = new Structure();
return someNewStructure;
}
You have to remember that this element was created within this function, and the function is transferring "responsibility" for the destruction of this object on to the caller. It is usually best to avoid this, though with large data structures it can't be. Another way to handle this is to define a copy constructor in your class so that you can do it the way you referenced. Without defining this copy constructor if you did this:
Sturcture someFunction() {
Structure someResultStruct;
return someResultStruct;
}
When you call someFunction in this case, if your class contained dynamic elements, or other complex data types, they are not guaranteed to copy correctly on return, and you will get weird behavior... unless you define your own copy constructor.

Best practice for std::auto_ptr

I'm just getting used to smart pointers using std::auto_ptr.
Assume that I want to call a function with both auto_ptr and normal Pointers.
auto_ptr<uint32> data_smart(new uint32[123])]);
uint32 data_fix[123];
uint32* data_dumb = new uint32[123];
processData(data_smart);
processData(data_fix);
processData(data_dumb);
What is the best practice for this without overloading? Having the processData function with a uint32* argument? Can I cast the smart pointer to uint32* for this case with .get()? Or what is the way I should do it?
Thanks in advance!
1.
auto_ptr<uint32> data_smart(new uint32[123])]);
Don't do that. auto_ptr works with scalars only (it calls delete rather than delete[]).
2.
auto_ptr owns the object it points to, so unless you want to pass the ownership to that function (in your code you don't), the function should accept a normal pointer. So you should change the call to:
processData(data_smart.get());
in order to explicitly express that data_smart continues to own the object.
EDIT: Noah Roberts' comment on your question is the bigger issue here, but this answers the question asked even if the example code is wrong....
... without overloading ...
If you want to do it without overloading, the only option that's going to work for all of these is to make the method take a dumb pointer parameter.
Can I cast the smart pointer to uint32* for this case?
No. Use std::auto_ptr<t>::get().
First of all, you don't initialize auto_ptr with a pointer to array. It's not supported, and you'll end up with memory leaks. std::auto_ptr handles only single objects.
If you still want to use std::auto_ptr, but for single objects only, you need to remember that std::auto_ptr transfers ownership in copy constructor. That means that your local auto_ptr (data_smart) won't hold any memory after you call processData if you pass data_smart by value.
In the end, you probably want to use boost::scoped_array or boost::shared_array.
Best practice is to not use auto_ptr. It will be deprecated in C++0x and replaced by std::unique_ptr (Reference: C++0x Draft Standard, Appendix D, Paragraph 10). In the meantime, alternatives include std::tr1::shared_ptr and boost::scoped_ptr.
But your example is an array, and those pointer types are not for arrays. You can use boost::shared_array for that.
However the Standard itself does not have array smart pointers. That’s probably because they believe you should be using std::vector instead (or std::array for fixed size arrays when you know the size at compile time). Given that, you could do the following:
std::vector<uint32> dataVector;
data.reserve(123);
// or, if the size is always 123:
std::tr1::array<uint32, 123> dataArray;
Now, you can call your function that accepts a regular plain-old uint32* because both vectors and std::tr1::arrays have methods to give you access to the data as a pointer to a C-style array:
processData(&dataVector[0]);
processData(dataArray.data());
I would strongly recommend adding bounds-checking if you are going to do this. Pass a second argument to processData with the size of the array:
processData(&dataVector[0], dataVector.size());
And if you can abandon C-style pointer/arrays entirely, a better way might be to pass by reference:
void processData(std::vector<uint32>& data) {
// process the data
}
// call it like this:
processData(dataVector);
But this only works for vectors, not std::tr1::arrays or any other container. So, taking it one step further, you could use a template that accepts iterators:
template <class AnIterator>
void processData(AnIterator begin, AnIterator end) {
for (AnIterator it = begin; it != end; ++it) {
// process each item
}
}
// call it like this
processData(dataVector.begin(), dataVector,end());
// or like this
processData(dataArray.begin(), dataArray.end());
// or even like this (assume c_data is a C-style array):
processData(c_data, c_data + number_of_items_in_c_data);
The last one works because pointers to C-style arrays can be used as iterators.
In your situation using a vector is the safest choice:
std::vector<uint32> data(123);
The signature of processData should ideally be:
void processData(const std::vector<uint32> & data);
However, this one is more frequently used:
void processData(uint32 * bytes, int length);
In both cases you can use the vector:
// 1
processData(data);
// 2
processData(data.data(), data.size());
Not withstanding why you should want to use auto and dumb (as you put it) pointers for the same data to the same name function without overloading, auto_ptr cannot be used on arrays because it calls the wrong sort of delete.
Have a look at this: http://learningcppisfun.blogspot.com/2007/05/custom-deleters-with-smart-pointers.html
Also have a look at this SO question regarding smart pointers to arrays: auto_ptr for arrays
It amuses me that the data_smart variable is the dumbest of the three. That is, when that scope ends, the auto_ptr destructor is going to call delete on its pointer and not delete[] which leads to UB (which is worse than the possible memory leak from data_dumb).
So, the point is don't use auto_ptr for arrays, use vector.
Onto the real question. First, if possible use reference arguments instead of pointer arguments. If this isn't possible use bare pointers and auto_ptr::get() gives access to the underlying pointer.
Ignoring the already HAMMERED don't use auto_ptr on array.
What is the best practice for this without overloading?
It appears your method will not take ownership, so the remaining question is will it be changed?
Having the processData function with a uint32* argument?
processData( uint32* ) Thats one option, but maybe not the best.
processData( uint32[123] ) if your not editing (123 is starting to push some copying).
processData( uint32 &[123] ) by ref and apply const as necessary.
Can I cast the smart pointer to uint32* for this case with .get()?
You can get the pointer content of the smart pointer using get(), it's already 'typed' so no need to cast it.
Aside:
Data and manipulation of at such a raw level should be in the one class, you probably don't even need to pass what should be a member variable into a member function.