tags:

views:

450

answers:

5

I have some

std::list<char> list_type

Now I have to supply contents of the list as (char *data, int length). Is there convenient way to present list contents as pointer and length? Does <vector> has such interface?

Thank you in advance.

A: 

list is a linked list data structure. There's no way you could do that (theoretically) without conversion.

You'll be able to access (C++0x Draft 23.2.6.3) the backing store of a vector with .data() in C++0x. Currently, your best bet is to treat it as an array by taking the address of the initial element.

Mehrdad Afshari
+1  A: 

You can do this with vector, not with list. A vector is guaranteed to be a contigous chunk of memory so you can say:

char *data = &list_type[0];
std::vector<char>::size_type length = list_type.size();
Logan Capaldo
+3  A: 

You can do it with a vector, because its data is stored contiguously:

std::vector<char> vec;

char* data = &vec[0];
int length = static_cast<int>(vec.size());

For list, you have to copy the data to an array. Luckily, that too is fairly easy:

std::list<char> list:
int length = static_cast<int>(list.size());
char* data = new char[length]; // create the output array
std::copy(list.begin(), list.end(), data); // copy the contents of the list to the output array

Of course, you're then left with a dynamically allocated array you have to free again.

jalf
It is probably a good idea to use static_cast<int>(list.size()) or static_cast<int>(vec.size()), since the result of size() is of type size_t which might or might not be convertible to int on some platforms.
Michael Aaron Safyan
Good answer, +1. But why not the best of both worlds -- std::copy to a std::vector<char>?
Pukku
Agree with Pukku except no need to std::copy to the vector, use the two-iterator constructor.
Steve Jessop
what's the point in copying it to a vector, if he needs it in char*/length format? He's going to pass the data as an array anyway, so what would we gain by putting it in an intermediary vector? It's not like it would be any safer. (And true about the size_t/int thing)
jalf
A vector can be "used as an array" - the reason it guarantees contiguous storage is precisely in order that its contents can be passed into C-style APIs taking start pointer and length. And it has the advantage over allocating an array with new[] that it provides RAII-style resource management.
Steve Jessop
yes, but that assumes the array is actually passed around and stored. He asked specifically for the data as a char* + length, which could very well mean he's going to pass it to another function, which doesn't know it belongs to a vector, and perhaps stores the pointer assuming it'll stay valid. Without knowing more context, it's silly to pretend that a vector is going to solve any problems. It might just as well blow up because the pointer is passed to a function which takes ownership of it, and frees it itself, causing a double-free when the vector does the same. We don't know the context.
jalf
I don't understand why you apply different standards in the first part of your answer, than in the second part. The suitability of a vector is assumed in the first part, so I don't see why in the second part, the data suddenly "has to be" copied into an array allocated with new, and not a vector.
Steve Jessop
I'm just trying to stick to the question. He asked if it was possible to get from list to array, and from vector to array, so I showed the simplest way to do each of those. I assumed he'd be able to figure out how to copy from list to vector himself if he felt there's any benefit in that. I don't know if there is, because I don't know the context of the question. The RAII properties of a vector might be useful in his case, or they might not. My goal was just to show the simplest, clearest, way to get a pointer to an array if you have a list and a vector respectively.
jalf
The question doesn't mention arrays. It asks whether it was possible to get a pointer and a length for the data in a vector or a list. In the case of a list, clearly it has to be copied into some kind of contiguous storage. I don't think that anything in the question suggests that a heap-allocated array is preferable to any other form of contiguous storage. I disagree that you've shown the simplest, clearest way to get pointer/length from a list: std::vector<char> myvec(mylist.begin(),mylist.end()), followed by your own vector code, is clearer and cleaner than new char[].
Steve Jessop
+1  A: 

I don't know about std::list, but std::vector does:

std::vector<char> list_type;

...

foo(&list_type[0], list_type.size())

std::string can do the job too, but you probably already know it.

dimba
A: 

You cannot do this with a list, as a list saves its data in list nodes. However, you can do this with a vector, which is guaranteed to store its data in a contiguous piece of memory. You can use either &v[0] or &*v.begin() to get a pointer to its first element:

void f(std::list<char>& list)
{
  std::vector<char> vec(list.begin(),list.end());
  assert(!vec.empty());
  c_api_function(&vec[0],vec.size());
  // assuming you need the result of the call to replace the list's content
  list.assign(vec.begin(),vec.end());
}

Note that the vector will automatically free its memory when the function returns. There are (at least) two more noteworthy things:

  • The vector must not be empty. You are not allowed to access v[0] of an empty vector. (Neither are you allowed to dereference v.begin().)
  • Since dynamic allocation is involved, converting back and forth between std::list and std::vector can be a real performance killer. Consider switching to std::vector altogether.
sbi