Is it safe to have a std::array of dynamic object, for example std::array<std::string, 3>, and to resize the contents (the strings) ? (because it can be problematic to have a raw C array of strings)
Yes, because std::array is a just a friendly template that wraps an underlying C style aray array. You can think of it as something like this:
template <typename T, int size>
class Array {
...
T vals[size];
}
Change T to string above and you'll quickly realize that anything that you can do to the contents of an array of strings you can do with a std::array of strings. This includes resizing, deleting, whatever you can imagine.
To think even deeper about it, think about it this way. The std::array holds a string. The string has no idea where its being held. The array might tell the string to make a copy of itself (through a copy constructor or assignment), when say the array itself is assigned. However, this is its entirely through the string's public interface. The fact that the string is being held by any data structure doesn't limit that string's functionality, it just makes the holder (in this case std::array) yet another client of the string's public interface.
As containers like std::array need to work with a large variety of types, they tend to make relatively few typically well documented assumptions on the type T passed in. Stuff like requiring that T can be copy constructed, default constructed, and assigned. Then its typically up to the implementer* of T to ensure these few assumptions are valid.
*There is a very advanced topic called template specialization where one could write a specialized version of array just for say "string". Aside from vector<bool> these are pretty rare with the standard containers.
Assuming you mean resizing the strings, then yes.
Related
I am trying to connect two existing codebases — one in C, the other in C++. The C++ code uses std::vector whereas the other one is based on arrays of double. I would like to pass arrays of double from the C code, perform operations on std::vectors in the C++ code, and eventually have these operations reflected in the arrays of double.
Is it possible to create a std::vector that matches the memory occupied by the array of double?
I have tried several options, but they all involve the creation of a new vector and a copy of the array of double into that vector. For instance:
void fcn(double* a, int sizeofa)
{
std::vector<double> vect_a;
vect_a.assign(a, a + sizeofa);
// operations on vect_a
for (int i=0;i<sizeofa;i++) { a[i] = vect_a[i]; }
}
As noted in the comments, std::vector manages its own memory, you can't make it use some other memory as the backing store (it would have no idea what to do if the size changed, among other issues).
But you may not need a vector at all; if you're just using vector for non-dynamic size related features, it's highly likely you could just use the functions from <algorithm> to perform the same work directly on the array that you wanted to use vector's methods to accomplish.
In C++, functions requiring a container often denote the container by Iterator pairs, which are templated. This is very convenient, especially when interfacing with external libraries, because an iterator isn't a type. It is a concept, which is just an interface that defines what a type should look like. Turns out, C style pointers are valid iterators. This means that you can use any C++ function that accepts an iterator with any C array.
So, now to answering your question. In other answers, it was made clear that you cannot make a std::vector control the memory allocated by a C array because a std::vector requires full ownership over the data because it wouldn't know how to deallocate it. You can copy the C array into a vector, but there is no point in using a std::vector unless you want it's resizing capabilities.
In summary: try not to pass std::vectors into functions because iterators are more generic. If you must avoid templates (virtual function, etc) than use a C style array because those are very flexible too, you can turn a std::vector into a C array, but the other way requires a copy.
I know this is hard if you have already made your code interface with std::vectors, in which case a copy is the only possible way. Prefer C style arrays when you don't need to resize the array, and maybe in the future std::array_view
I have been overthinking (some may say underthinking, let's see what happens) the const-ness of STL containers and their elements.
I have been looking for a discussion of this, but the results have been surprisingly sparse. So I'm not necessarily looking for a definite answer here, I'd be just as happy with a discussion that gets the gears in my head moving again.
Let's say I have a class that keeps std::strings in a std::vector. My class is a dictionary that reads words from a dictionary file. They will never be changed. So it seems prudent to declare it as
std::vector<const std::string> m_myStrings;
However, I've read scattered comments that you shouldn't use const elements in a std::vector, since the elements need to be assignable.
Question:
Are there cases when const elements are used in std::vector (excluding hacks etc)?
Are const elements used in other containers? If so, which ones, and when?
I'm primarily talking about value types as elements here, not pointers.
My class is a dictionary that reads words from a dictionary file. They will never be changed.
Encapsulation can help here.
Have your class keep a vector<string>, but make it private.
Then add an accessor to your class that returns a const vector<string> &, and make the callers go through that.
The callers cannot change the vector, and operator [] on the vector will hand them const string &, which is exactly what you want.
No, for the reason you state.
In the context of std::vector, I don't think it makes sense to use a const qualifier with its template parameter because a std::vector is dynamic by nature and may be required to "move" in memory in order to "resize" itself.
In the C++03 standard, std::vector is guaranteed stored in contiguous memory. This almost requires that std::vector be implemented with some form of an array. But how can we create a dynamic size-changing array? We cannot simply just "append" memory to the end of it--that would either require an additional node (and a linked list) or actually physically putting our additional entries at the end of the array, which would be either out-of-bounds or require us to just reserve more memory in the first place.
Thus, I would assume that std::vector would need to allocate an additional array, copy or move its members over to the end array, and then delete the old one.
It is not guaranteed that a move or copy assignment for every template-able object for a std::vector would not change the underlying object being moved or copied--it is considered good form to do add the const qualifier, but it is not required. Therefore, we cannot allow a std::vector<const T>.
Related: How is C++ std::vector implemented?
consider using
std::vector<std::shared_ptr<const std::string>>
instead?
I'm pretty new to C++, so I apologize if the answer to this is obvious.
I've been writing an STL-style custom data structure as a way to improve my skills. (I actually do have a practical need for this structure as well, but I'm going a little overboard for study purposes.)
This structure needs to dynamically resize (like a vector), and in my first draft, I made the underlying "container" a C-style array and did all the allocations and de-allocations manually. I'm refactoring, and I'd like to use a C++11-style std::array as my underlying structure, just to make the code a little cleaner. My problem is that I don't know how to declare the array class member in a way that allows for resizing. Since different template parameters entail a different type, I can't just declare a member as array and then assign the same variable to an array upon resize.
I thought about declaring a member for each potential size, like
private:
array<T, 8>
array<T, 16>
array<T, 32>
...
but I don't want each of those arrays default constructing T members.
Is there a clean solution here? Or do I just have to stick with C-style arrays?
Thanks for the help.
EDIT:
After re-reading my question, I don't think it makes sense, actually. I understood that std::array's size had to be known at compile time, but for some reason my brain to infer that my goal was impossible. It seems obvious to me now that I'm stuck with C-style arrays and the heap. I think I just needed to write it out to get perfectly clear.
Thanks for your answers.
std::array represents an array whose size is known statically (i.e. at compile time), so it cannot be used in cases such as this where the size will be only known at runtime.
Simply use std::vector instead, it has a constructor that takes the size as its argument.
std::array is specifically designed not to be resizable. It's mainly a workaround for the fact that fixed-size arrays aren't first-class value types.
The only use case that I can think of is some sort of externalized or serialized object (stored on disk or delivered over socket, or something along those lines), where there is a dynamically sized component. If you already have a format defined for that, then you should probably stick with what you have. Trying to reuse std::array<> for this will not work if the sizes are not known at compile time.
If you want to refactor, what might be useful would be a template class that can take a C array as a constructor argument, but provide an STL container interface to it.
Since std::list and std::vector exist, is there a reason to use traditional C arrays in C++, or should they be avoided, just like malloc?
In C++11 where std::array is available, the answer is "yes, arrays should be avoided". Prior to C++11, you may need to use C arrays to allocate arrays in the automatic storage (i.e. on the stack).
Definitely, although with std::array in C++11, practically only for
static data. C style arrays have three important advantages over
std::vector:
They don't require dynamic allocation. For this reason, C style
arrays are to be preferred where you're likely to have a lot of very
small arrays. Say something like an n-dimension point:
template <typename T, int dims>
class Point
{
T myData[dims];
// ...
};
Typically, one might imagine a that dims will be very small (2 or 3),
T a built-in type (double), and that you might end up with
std::vector<Point> with millions of elements. You definitely don't
want millions of dynamic allocations of 3 double.
The support static initialization. This is only an issue for static
data, where something like:
struct Data { int i; char const* s; };
Data const ourData[] =
{
{ 1, "one" },
{ 2, "two" },
// ...
};
This is often preferable to using a vector (and std::string), since it
avoids all order of initialization issues; the data is pre-loaded,
before any actual code can be executed.
Finally, related to the above, the compiler can calculate the actual
size of the array from the initializers. You don't have to count them.
If you have access to C++11, std::array solves the first two issues,
and should definitely be used in preference to C style arrays in the
first case. It doesn't address the third, however, and having the
compiler dimension the array according to the number of initializers is
still a valid reason to prefer C style arrays.
Never say "never", but I'd agree that their role is greatly diminished by true data structures from STL.
I'd also say that encapsulation inside objects should minimize the impact of choices like this. If the array is a private data member, you can swap it in or out without affecting clients of your class.
I have worked on safety critical systems where you are unable to use dynamic memory allocation. The memory has to always be on the stack. Therefore in this case you would use arrays as the size is fixed at compile time.
array in c++ gives you fixed size fast alternative of dynamic sized std::vector and std::list. std::array is one of the additions in c++11. It provides the benefit of std containers while still providing the aggregate type semantics of C-style arrays.
So in c++11 i'd certainly use std::array, where it is required, over vector. But i'd avoid C style array in C++03.
Most usually, no, I can't think of a reason to use raw arrays over, say, vectors. If the code is new.
You might have to resort to using arrays if your libraries need to be compatible with code that expects arrays and raw pointers.
I know a lot of people are pointing out std::array for allocating arrays on the stack, and std::vector for the heap. But neither seem to support non-native alignment. If you're doing any kind of numeric code that you want use SSE or VPX instructions on (thus requiring 128 or 256 byte alignment respectively), C arrays would still seem to be your best bet.
I would say arrays are still useful, if you are storing a small static amount of data why not.
The only advantage of an array (of course wrapped in something that will manage automatically its deallocation when need) over std::vector I can think about is that vector cannot pass ownership of its data, unless your compiler supports C++11 and move constructors.
C style arrays are a fundamental data structure, so there will be cases when it is better to use it. For the general case, however, use the more advanced data structures that round off the corners of the underlying data. C++ allows you to do some very interesting and useful things with memory, many of which work with simple arrays.
You should use STL containers internally, but you should not pass pointers to such containers between different modules, or you will end up in dependency hell. Example:
std::string foo;
// fill foo with stuff
myExternalOutputProc(foo.c_str());
is a very good solution but not
std::string foo;
// fill foo with stuff
myExternalOutputProc(&foo);
The reason is that std::string can be implemented in many different ways but a c-style string is always a c-style string.
I'd like to use a std::vector to control a given piece of memory. First of all I'm pretty sure this isn't good practice, but curiosity has the better of me and I'd like to know how to do this anyway.
The problem I have is a method like this:
vector<float> getRow(unsigned long rowIndex)
{
float* row = _m->getRow(rowIndex); // row is now a piece of memory (of a known size) that I control
vector<float> returnValue(row, row+_m->cols()); // construct a new vec from this data
delete [] row; // delete the original memory
return returnValue; // return the new vector
}
_m is a DLL interface class which returns an array of float which is the callers responsibility to delete. So I'd like to wrap this in a vector and return that to the user.... but this implementation allocates new memory for the vector, copies it, and then deletes the returned memory, then returns the vector.
What I'd like to do is to straight up tell the new vector that it has full control over this block of memory so when it gets deleted that memory gets cleaned up.
UPDATE: The original motivation for this (memory returned from a DLL) has been fairly firmly squashed by a number of responders :) However, I'd love to know the answer to the question anyway... Is there a way to construct a std::vector using a given chunk of pre-allocated memory T* array, and the size of this memory?
The obvious answer is to use a custom allocator, however you might find that is really quite a heavyweight solution for what you need. If you want to do it, the simplest way is to take the allocator defined (as the default scond template argument to vector<>) by the implementation, copy that and make it work as required.
Another solution might be to define a template specialisation of vector, define as much of the interface as you actually need and implement the memory customisation.
Finally, how about defining your own container with a conforming STL interface, defining random access iterators etc. This might be quite easy given that underlying array will map nicely to vector<>, and pointers into it will map to iterators.
Comment on UPDATE: "Is there a way to construct a std::vector using a given chunk of pre-allocated memory T* array, and the size of this memory?"
Surely the simple answer here is "No". Provided you want the result to be a vector<>, then it has to support growing as required, such as through the reserve() method, and that will not be possible for a given fixed allocation. So the real question is really: what exactly do you want to achieve? Something that can be used like vector<>, or something that really does have to in some sense be a vector, and if so, what is that sense?
Vector's default allocator doesn't provide this type of access to its internals. You could do it with your own allocator (vector's second template parameter), but that would change the type of the vector.
It would be much easier if you could write directly into the vector:
vector<float> getRow(unsigned long rowIndex) {
vector<float> row (_m->cols());
_m->getRow(rowIndex, &row[0]); // writes _m->cols() values into &row[0]
return row;
}
Note that &row[0] is a float* and it is guaranteed for vector to store items contiguously.
The most important thing to know here is that different DLL/Modules have different Heaps. This means that any memory that is allocated from a DLL needs to be deleted from that DLL (it's not just a matter of compiler version or delete vs delete[] or whatever). DO NOT PASS MEMORY MANAGEMENT RESPONSIBILITY ACROSS A DLL BOUNDARY. This includes creating a std::vector in a dll and returning it. But it also includes passing a std::vector to the DLL to be filled by the DLL; such an operation is unsafe since you don't know for sure that the std::vector will not try a resize of some kind while it is being filled with values.
There are two options:
Define your own allocator for the std::vector class that uses an allocation function that is guaranteed to reside in the DLL/Module from which the vector was created. This can easily be done with dynamic binding (that is, make the allocator class call some virtual function). Since dynamic binding will look-up in the vtable for the function call, it is guaranteed that it will fall in the code from the DLL/Module that originally created it.
Don't pass the vector object to or from the DLL. You can use, for example, a function getRowBegin() and getRowEnd() that return iterators (i.e. pointers) in the row array (if it is contiguous), and let the user std::copy that into its own, local std::vector object. You could also do it the other way around, pass the iterators begin() and end() to a function like fillRowInto(begin, end).
This problem is very real, although many people neglect it without knowing. Don't underestimate it. I have personally suffered silent bugs related to this issue and it wasn't pretty! It took me months to resolve it.
I have checked in the source code, and boost::shared_ptr and boost::shared_array use dynamic binding (first option above) to deal with this.. however, they are not guaranteed to be binary compatible. Still, this could be a slightly better option (usually binary compatibility is a much lesser problem than memory management across modules).
Your best bet is probably a std::vector<shared_ptr<MatrixCelType>>.
Lots more details in this thread.
If you're trying to change where/how the vector allocates/reallocates/deallocates memory, the allocator template parameter of the vector class is what you're looking for.
If you're simply trying to avoid the overhead of construction, copy construction, assignment, and destruction, then allow the user to instantiate the vector, then pass it to your function by reference. The user is then responsible for construction and destruction.
It sounds like what you're looking for is a form of smart pointer. One that deletes what it points to when it's destroyed. Look into the Boost libraries or roll your own in that case.
The Boost.SmartPtr library contains a whole lot of interesting classes, some of which are dedicated to handle arrays.
For example, behold scoped_array:
int main(int argc, char* argv[])
{
boost::scoped_array<float> array(_m->getRow(atoi(argv[1])));
return 0;
}
The issue, of course, is that scoped_array cannot be copied, so if you really want a std::vector<float>, #Fred Nurk's is probably the best you can get.
In the ideal case you'd want the equivalent to unique_ptr but in array form, however I don't think it's part of the standard.