Question

Is there a way to use RAII when creating an array in C++, or do I have to resort to manual memory management via the "new" keyword?

EDIT: By request, some additional details:

First my disclaimer: I'm fairly novice at C++.

Now the details: I simply wanted to iterate through an existing array, SomeClass source[], and parse each element into a storage array, string results[].

So to create that storage string results[], do I need to say string results[] = new string[source.size()] or is there a way to avoid the "new" keyword here via RAII techniques?

It sounds like I'm hearing vector is the way to go. Still, wondered if it's possible with a plain old array.

Était-ce utile?

La solution

In C++, especially since we're talking about RAII, we really shouldn't be using C-style arrays at all. The Standard Library provides many containers with different properties that obviate most needs for C-style arrays. By default, you should be using std::vector<> unless you have an understanding of the other containers and a compelling reason not to 1.

Judging from your comments, it looks like what you're trying to do is build an array of string data. This is simple in modern C++ -- just use a std::vector <std::string>.

int main()
{
  std::vector <std::string> myStrings;
  myStrings.push_back ("hello");
  myStrings.push_back ("goodbye");
}

This achieves all your mentioned goals of being RAII and no need to new or delete anything. It also integrates very nicely with other Standard Library facilities, such as find.

I did say "obviate most needs," emphasis mine. There is still occasional need to go old-school. I won't discuss them here since if you actually need it you already know. Which is to say, if you don't know you probably don't need it.

All that being said, std::unique_ptr does support managing C-style arrays with special syntax:

std::unique_ptr <unsigned []> myArray (new unsigned [256]);

the array managed by myArray above will be properly deleted with delete [] at destruction time.

Since there is no unique_ptr analogue to shared_ptr's make_shared, you will either have to use new to actually construct the array, or provide your own (or someone else's) implementation of make_unique


Sidebar: make_unique will be added to C++14.


1 " you should be using std::vector<> unless you have an understanding of the other containers and a compelling reason not to"

This isn't just my opinion. It's also the general (unofficial) opinion of StackOverflow as a whole, C++'s creator Bjarne Stroustup, and the C++ Standard itself (23.1.1).

Autres conseils

std::vector<T> is an RAII array type. From the additional information you've given std::vector<string> is appropriate for your use.


string results[] = new string[source.size()]

Just as an aside about arrays, this syntax isn't correct for C++. People teaching C and C++ often teach that arrays and pointers are the same thing, but this is not true and the syntax above shows one of the ways they differ.

The actual relationship between arrays and pointers is

  • Arrays and pointers are distinct types
  • In many contexts an implicit conversion from an array to pointer is applied. The conversion results in the address of the array's first element.
  • pointer arithmetic is defined such that if a pointer points to an element in an array then you can get pointers to other elements of the array by adding and subtracting to the pointer value.
  • In a some contexts writing an array type will result in a pointer type. In particular, function parameters declared to be of array types are adjusted to be of pointer type. E.g. void foo(int[10]); is effectively identical to void foo(int*);.

So the code you show is declaring an array and initializing it with a pointer. This will result in an error because there's no conversion from pointers to arrays.

Generally you should avoid raw arrays in C++; Arrays just have too many weird rules, such as the weird function parameter rule described above, the rules about when exactly the implicit conversion is performed, prohibitions on assignment and returning arrays from functions, etc. When starting out it's probably best to just stick with the std::array template for arrays with a size known at compile time and the std::vector template for arrays with a size not known at compile time.

You can use std::vector<string> and push_back() each result string in to the vector. You don't have to use new unless you want to avoid vectors and manage memory by yourself

I think a simple template would do the trick in the general case:

template<class T>
class HeapArray {
    T* ptr = nullptr;
public:
    HeapArray(int size) { ptr = new T[size]; }
    ~HeapArray() { delete [] ptr; }
    operator T*() { return ptr; }
};

You use it as:

HeapArray<std::string> results(source.size());
results[i] = "how cool is this";

basically the HeapArray object is automatically cast'd to its member pointer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top