How can I create a Modifiable Const vector but make it unable to be resized? Either that OR I want to return a pointer from a function but not allow the user to delete it.

This is my example so far:

class MemberRawArrayVector
{
    private:
        vector<unsigned char> MemberRawArray;

    public:
        MemberRawArrayVector(int Size) : MemberRawArray(Size) {}

        void SetMemberValue(char Value, int Index) { MemberRawArray[Index] = Value; }

        const vector<unsigned char>* GetMemberArray() { return &MemberRawArray; }
};

class RawMemberArray
{
    private:
        unsigned char* RawArray;

    RawMemberArray(int Size) : RawArray(new unsigned char[Size]) {}
    ~RawMemberArray() { delete[] RawArray; }

    void SetMemberValue(char Value, int Index) { RawArray[Index] = Value; }

    unsigned char* GetMemberArray() { return RawArray; }
};

In the first class with vectors, it returns the member array and it is read only to prevent resizing. Thing is, I want to be able to modify the values in it without the SetMemberValue function.

In the second class, I return the raw pointer but as we know, the user can easily delete this pointer before the destructor gets to it. I want to prevent deletion by force! Inother words I want them to have access to the pointer but at the same time not allow them to delete it at all. Only the class should be able to do deletion. I cannot have a const pointer because I need to modify the values it points to.

This is the reason I created the two classes as examples. One has what the other doesn't. The vector can't be delete/resized but it also can't be modified. The raw pointer can be modified and deleted!

Is this impossible? I don't want to use SetMemberValue function.. I'd prefer the pointer over the vector if it has such a solution or maybe both so I can choose but I'm a bit skeptical on whether this is possible or not.
Note: I also tried Smart Pointers with a custom deleter but then realize SmartPointers can also be deleted.

Edited 4 Years Ago by triumphost

Why not overload teh access functions to limit them yourself? For example

unsigned char operator[](size_t i) {
   if (i < 0 || i > vector_max) {
      throw some exception...
   }
   return internalVector[i];
}

^Because the accessor functions only allow you to access one element at a time unless a for-loop is used. I want to return the entire array rather than just one element at an index.

Either manually make sure the vector size isn't correct, or use an static array, or inherit from vector and make the resize function private.

I think you need a little lesson in common practices and idiomatic C++ programming.

In the first class with vectors, it returns the member array and it is read only to prevent resizing. Thing is, I want to be able to modify the values in it without the SetMemberValue function.

First of all, in any case, you probably don't want to return a pointer (or reference) to the vector because that just exposes too much of the internals of your class. As for what you want to achieve, let me think, you want to be able to access all the elements in the vector, be able to modify them, but not be able to resize the vector. There is a well established practice to do exactly that, it is called "iterator ranges". Typically, you would do this:

class MemberRawArrayVector
{
    private:
        vector<unsigned char> MemberRawArray;
    public:
        typedef vector<unsigned char>::iterator iterator;
        typedef vector<unsigned char>::const_iterator const_iterator;

        MemberRawArrayVector(int Size) : MemberRawArray(Size) {}
        void SetMemberValue(char Value, int Index) { MemberRawArray[Index] = Value; }
        // either this:
        iterator begin() { return MemberRawArray.begin(); };
        const_iterator begin() const { return MemberRawArray.begin(); };
        iterator end() { return MemberRawArray.end(); };
        const_iterator end() const { return MemberRawArray.end(); };

        // or this (or both):
        std::pair< iterator, iterator > range() { 
            return std::make_pair(MemberRawArray.begin(), MemberRawArray.end()); 
        };
        std::pair< const_iterator, const_iterator > range() const { 
            return std::make_pair(MemberRawArray.begin(), MemberRawArray.end()); 
        };
};

Just about any functions that you might want to write that does anything with the elements in an array (or list, or whatever) can be formulated in terms of an iterator range [begin, end). Take all the STL algorithms for example. This is the idiomatic way to get access to all the elements of a container, and it doesn't allow for resizing (or deletion).

In the second class, I return the raw pointer but as we know, the user can easily delete this pointer before the destructor gets to it.

The user can call delete on the pointer, but will he do it? Have you ever seen code like this: std::string s = "Hello World"; delete[] s.c_str();? I hope not! Everybody knows that you don't delete a pointer that you obtained from an object member function (or any other function for that matter). This is such a pervasive practices and it is very important that you understand it. You never allocate memory inside a function (using new) and then return the pointer, expecting the user to eventually call delete on it. You just don't do that, period. These are the main choices:

  • The allocated memory is owned by an object and any pointers given out are not to be deleted;
  • The allocated memory is managed by a smart-pointer (e.g., unique_ptr or shared_ptr), which means that the deletion logic is bundled with the pointer, and will be invoked automatically;
  • At worse, you can have two functions, one that clearly states that it does the allocation of the memory, and one that clearly states that it does the deallocation of the memory. Something like "CreateImage()" and "FreeImage()" where it is made clear to the user that the pointer obtained from the first function has be newly allocated, and that it must be deleted through the second function only.

What this boils down to is that as a programmer, you never delete a pointer that you got from anywhere, except if you allocated it with new yourself. So, rest assured, nobody is going to delete the pointers you serve them.

I want to prevent deletion by force! Inother words I want them to have access to the pointer but at the same time not allow them to delete it at all.

This can certainly be done with a simple smart-pointer, but, as I said, you don't need to.

Comments
+1 Thinks way outside of the box! Excellent answer!

Ah mike thank you for that lesson! BUT I have seen users delete pointers they have gotten from objects. Some do it because they come from a language such as C# and do not understand when to use delete and others do it just for testing what will happen. So I was just thinking in terms of making an object absolutely fool proof. I myself would not delete a pointer from my own object or some library or anyone else's code unless it provides a way to do that as you mentioned.

But what you have given is the best idea using the std::pairs and iterators. I never thought about that and never thought that anyone would suggest that. That really really does help the most! I was playing around with it at first and using the pointer to the vector to gain access to begin and end iterators. I like the std::pair solution thought so I think I'll go with that.

Edited 4 Years Ago by triumphost

If you like the std::pair solution, then you should be aware of a neat little function called std::tie (also available in Boost, for pre-C++11, as boost::tie). This function basically constructs a pair (or generally, a tuple) of references to its given parameters. This allows for this type of code:

MemberRawArrayVector my_vect;
MemberRawArrayVector::iterator it, it_end;  // declare two iterators.
for(std::tie(it,it_end) = my_vect.range(); it != it_end; ++it) {
  /*  do whatever  */
};

This tie function is pretty useful for all sorts of schemes where you return a tuple (or pair) from a function (as opposed to the traditional solution of giving pass-by-reference parameters to store additional result-values of a function).

This question has already been answered. Start a new discussion instead.