Can't copy NSArray to std::vector using ARC - nsarray

I am trying to Objective-C++ to copy the contents of an NSArray into an std::vector in a project that is using automatic reference counting.
When I write this:
NSArray* array;
...
std::vector<id> buffer;
buffer.reserve(array.count);
[array getObjects:&buffer[0] range:NSMakeRange(0, array.count)];
The call to getObjects:range: results in this error:
Cannot initialize a parameter of type '__unsafe_unretained id *' with an rvalue of type '__strong id *'
Some searching on the web indicated that maybe a __bridge cast was needed. Using this code:
[array getObjects:(__bridge id*)&buffer[0] range:NSMakeRange(0, array.count)];
Results in this error:
Incompatible types casting '__strong id *' to '__strong id *' with a __bridge cast
What is needed to that the array objects can be copied into the vector?

I got my code to work by doing this;
std::vector<__unsafe_unretained id> buffer(array.count);
[array getObjects:&buffer[0] range:NSMakeRange(0, array.count)];
The vector is a local object on the stack inside a method, so it goes out of scope and won't need to hold onto the array elements

Related

How do you properly send an array from ROS in C++?

I'm using Kinetic.
I have a custom message path.msg
string path_name
segment[] segments
I'm trying to send a ROS goal with that message type.
I initialize an array in my code
cuarl_rover_planner::segment segments[path->getSegments().size()];
//do stuff that populates the array
cuarl_rover_planner::path action_path;
action_path.segments = segments; // Error here
I get this error
error: no match for ‘operator=’ (operand types are ‘cuarl_rover_planner::path_<std::allocator<void> >::_segments_type {aka std::vector<cuarl_rover_planner::segment_<std::allocator<void> >, std::allocator<cuarl_rover_planner::segment_<std::allocator<void> > > >}’ and ‘cuarl_rover_planner::segment [(<anonymous> + 1)] {aka cuarl_rover_planner::segment_<std::allocator<void> > [(<anonymous> + 1)]}’)
action_path.segments = segments;
I'm assuming that the action_path.segments take a different data type, but I don't understand what that datatype is, from that error message.
action_path.segments is a std::vector<segment>, but your segments variable is just a single segment, not a vector of segments. If you want to add only one segment, you can use action_path.push_back(segment). Otherwise, you can declare segments as
std::vector<cuarl_rover_planner::segment> segments(path->getSegments().size());
If you wanted to use a raw pointer array for some reason (like you might be here), you have to explicitly set that up as std::vector first, i.e.
action_path.segments = std::vector<cuarl_rover_planner::segment>(segments, segments+path->getSegments().size());
See How to initialize std::vector from C-style array? for more about setting a vector from a raw C-array.

Problem with passing list pointer to a function

In my program I have a list which is a pointer list<COffenceUnit*>* m_attack = nullptr; I initialize this list like that: m_attack = new list<COffenceUnit*>(); in the constructor. At some point in the code I want to send this list to another constructor as a reference. This is the constructor that receives the list:
GameMap::GameMap(const std::list<CDefenceUnit*>* &defenseUnits, const std::list<COffenceUnit*>* &offenseUnits)
{
mGameMap = new int* [GRID_SIZE];
for (int i = 0; i < GRID_SIZE; ++i)
mGameMap[i] = new int[GRID_SIZE];
updateMap(defenseUnits, offenseUnits);
}
However the compiler throws an error that says:
Error C2664 'GameMap::GameMap(const GameMap &)': cannot convert argument 1 from
'std::list<CDefenceUnit *,std::allocator<_Ty>> **' to 'const std::list<CDefenceUnit *,std::allocator<_Ty>> *&'
I can't figure out what am I doing wrong here.
You're trying to call the function with a pointer-to-pointer-to-list (std::list<...>**), but the function expects a pointer-to-list (std::list<...>*), so the conversion fails.
Dereference the argument to remove one level of pointer. For example if you had GameMap(defenseUnits), then change that to GameMap(*defenseUnits).
Also you should almost never new std containers, so to initialize your m_attack, it's recommended to do it without new (i.e. without dynamic allocation), like so:
list<COffenceUnit*> m_attack;
Then you also don't need to do m_attack = list<COffenceUnit*>(); later, because the list is already default initialized by the list's constructor.
This also helps you avoid multiple levels of pointers, such as in std::list<...>**.
Also you probably want std::vector instead of std::list, the latter is rarely a better choice.

unique_ptr<TStringList []> dsts(new TStringList[5]) fail

MyEnvironment:
C++ Builder XE4
I am trying to use array of TStringList using unique_ptr<>.
Following didn't give any error:
unique_ptr<int []> vals(new int [10]);
On the other hand, following shows error:
unique_ptr<TStringList []> sls(new TStringList [10]);
The error is 'access violation at 0x000000000: read of address 0x0000000'.
For TStringList, can't I use array of unique_ptr<>?
It isn't a unique_ptr issue: your attempt fails because you are trying to create an array of actual TStringList object instances instead of an array of pointers to TStringList instances (for further details you can take a look at How to create an array of buttons on Borland C++ Builder and work with it? and Quality Central report #78902).
E.g. You'll get an access violation even if you try:
TStringList *sls(new TStringList[10]);
(pointer to a dynamic array of size 10 and type TStringList).
You have to manage a pointer to a dynamic array of type TStringList *. Using std::unique_ptr:
std::unique_ptr< std::unique_ptr<TStringList> [] > sls(
new std::unique_ptr<TStringList>[10]);
sls[0].reset(new TStringList);
sls[1].reset(new TStringList);
sls[0]->Add("Test 00");
sls[0]->Add("Test 01");
sls[1]->Add("Test 10");
sls[1]->Add("Test 11");
ShowMessage(sls[0]->Text);
ShowMessage(sls[1]->Text);
Anyway, if the size is known at compile time, this is a better choice:
boost::array<std::unique_ptr<TStringList>, 10> sls;
(also take a look at Is there any use for unique_ptr with array?)

How to use new operator as mapped type in std::map?

I've got a problem with std::map. I try to implement map that mapped type should return pointer to new created object. Better explanation in code below:
std::map<char, abstract_operation_factory*> operations_map = boost::assign::map_list_of
('+', (new add_oper_factory))
('-', (new sub_oper_factory));
char operation = '+';
std::map<char, abstract_operation_factory*>::const_iterator it = operations_map.find(operation);
if (it != operations_map.end()) {
boost::shared_ptr<abstract_operation_factory> oper_factory(it->second);
}
I always get the same error from boost library.
/boost/preprocessor/iteration/detail/local.hpp:37: error: no matching function for call to 'std::pair<char, add_oper_factory*>::pair(const char&, sub_oper_factory* const&)'
BOOST_PP_LOCAL_MACRO(1)
^
Is an any option to do this?
When map_list_of sees this list...
('+', (new add_oper_factory))
('-', (new sub_oper_factory))
...it starts creating pairs based on the types of the first pair, but that then clashes with the type of the second pair. If you cast both pointers to abstract_operation_factory* you'll get past that:
('+', static_cast<abstract_operation_factory*>(new add_oper_factory))
('-', static_cast<abstract_operation_factory*>(new sub_oper_factory))
That said, when you later create...
boost::shared_ptr<abstract_operation_factory> oper_factory(it->second);
...you're asking the shared_ptr to take ownership of the dynamically allocated object - when the shared_ptr goes out of scope it will delete the object without removing it from the map. Perhaps you plan to take care of that, but if it's accidental you may want to instead store shared_ptrs in the map to too prevent this, or you may want to use it->second as a raw pointer without storing it in a shared_ptr.

Unable to convert a uint8_t vector iterator to a const uint8_t *

I have a vector object that contains clipboard data. I am trying to write the contents of the clipboard data into a temp file using a buffered stream. I am using iterators to access the contents of the vector.
I am running into trouble while trying to convert the clipboard data which is a std::vector ClipboardDataVector to inbuffer which of type const std::uint8_t* inBuffer.
Here is the code that I use
typedef std::vector ClipboardDataVector;
File::WriteBlock(const std::uint8_t* inBuffer, std::uint32_t inBufferSize);
BOOL WriteToTempFile(ClipboardDataVector& clipBoardData) {
std::vector::iterator clipBoardIterator;
clipBoardIterator = clipBoardData.begin();
File::WriteBlock((const uint8_t *)clipBoardIterator, clipBoardData.size());
}
When I compile this code I get the following error.
error C2440: 'type cast' : cannot convert from 'std::_Vector_iterator<_Myvec>' to 'const uint8_t *'
I am new to vectors and I am finding it hard to get my head around this error - how can I resolve it?
When you use a std::vector you need to specify the type it holds. So your typedef needs to be:
typedef std::vector<uint8_t> ClipboardDataVector;
Once you've done that if you have a vector of that type and you want to get a const uint8_t * the usual idiom is:
void WriteToTempFile(const ClipboardDataVector& clipBoardData) {
const uint8_t *data = clipBoardData.size() ? &clipBoardData[0] : NULL;
// ...
}
This works because vectors have contiguous storage - it's asking for a pointer to the first element in the vector. It also checks for the special case where the vector is empty and so the subscript operator can't be used. This clearly won't work for something like std::list where the elements aren't always contiguous.
You were on the right sort of track with iterators, but iterators are a generalisation of the concept of a pointer - that is they look and feel like a pointer (by either being a pointer or some operator overloading) but they're not necessarily going to actually be a pointer always. If you need a pointer from a vector (because you're interacting with C usually) then the address of the first element is the safe, portable way to do it.
(I also made the reference to clipBoardData be const also - it's a good habit to be in, marking things you won't alter as const always)