views:

465

answers:

9

we have a data structure

struct MyData
{
       int length ;
       char package[MAX_SIZE];  
};

where MAX_SIZE is a fixed value . Now we want to change it so as to support "unlimited" package length greater than MAX_SIZE . one of the proposed solution is to replace the static array with a pointer and then dynamically allocating the size as we require For EX

struct MyData
{
       int length ;
       char* package;  
};

and then

package = (char*)malloc(SOME_RUNTIME_SIZE) ;

Now my question is that is this the most efficient way to cater to the requirement OR is there any other method .. maybe using STL data structures like growable arrays etc etc . we want a solution where most of the code that works for the static char array should work for the new structure too ..

+1  A: 

Yep, I would use an STL vector for this:

struct
{
    std::vector<char> package;
    // not sure if you have anything else in here ?
};

but your struct length member just becomes package.size ().

You can index characters in the vector as you would in your original char array (package[index]).

Cannonade
A: 

What you have written can work and is probably the best thing to do if you do not need to resize on the fly. If you find that you need to expand your array, you can run

package = (char*)realloc((void*)package, SOME_RUNTIME_SIZE) ;

You can use an STL vector

include <vector>

std::vector<char> myVec();  //optionally myVec(SOME_RUNTIME_SIZE)

that you can then resize using myVec.resize(newSize) or by using functions such as push_back that add to the vector and automatically resize. The good thing about the vector solution is that it takes away many memory management issues -- if the vector is stack-allocated, its destructor will be called when it goes out of scope and the dynamically-allocated array underlying it will be deleted. However, if you pass the vector around, the data will get copied that can be slow, so you may need to pass pointers to vectors instead.

bsdfish
"package = (char*)realloc((void*)package, SOME_RUNTIME_SIZE) ;" -- Read the definition of realloc and figure out why you're not using it properly. Anyway the other person's answer was correct, std::string.
Windows programmer
I guess it depends how you are using this thing (I actually mean vector and have since edited my answer). Do you wan't a null terminated string or an array of characters?
Cannonade
+7  A: 

Much, much better/safer:

struct my_struct
{
    std::vector<char>package;  
};

To resize it:

my_struct s;
s.package.resize(100);

To look at how big it is:

my_struct s;
int size = s.package.size();

You can even put the functions in the struct to make it nicer:

struct my_struct
{
  std::vector<char>package;  

  void resize(int n) {
    package.resize(n);
  }
  int size() const {
    return package.size();
  }
};

my_struct s;
s.resize(100);
int z = s.size();

And before you know it, you're writing good code...

Jimmy J
Why encapsulate a single field into a struct? A typedef would be enough.
sharptooth
I think Jimmmy was assuming there is other stuff in there (I know I did).
Cannonade
Yes, I assume there's more to it. Also, struct is a stepping stone to proper encapsulation.
Jimmy J
Pardon the ignorance, but why would one want to make a structure with functions in it? It seems to me that that's what a class basically is. What am I missing?
Will Mc
you are missing that a struct and a class is the same - just with different default protection (private vs public). the choice is arbitrary. if more functions are public than private, struct is a good choice imho. but some crappy compilers moan (none that i know though)
Johannes Schaub - litb
As noted, struct and class are basically the same. I used "struct" because that's what he used and I was being as gentle as possible.
Jimmy J
Ok, thanks you guys. Oddly, a friend of mine asked a week ago if structs could have functions. I replied "That would be a class." Then I saw this example, and I doubted my conviction. Thanks again :)
Will Mc
It's probably good to think of struct/class as different and use them to express your "intent" in the source code, but the compiler sees them identically (apart from class having 'private' access by default)
Jimmy J
+4  A: 

using STL data structures like growable arrays

The STL provides you with a host of containers. Unfortunately, the choice depends on your requirements. How often do you add to the container? How many times do you delete? Where do you delete from/add to? Do you need random access? What performance gurantees do you need? Once you have a sufficiently clear idea about such things look up vector, deque, list, set etc.

If you can provide some more detail, we can surely help pick a proper one.

dirkgently
+1  A: 

use a deque. sure a vector will work and be fine, but a deque will use fragmented memory and be almost as fast.

gbrandt
well a deque as you say is not contiguous. that would be a major no-go for his requirements for that array replacement.
Johannes Schaub - litb
+2  A: 

I would also wrap a vector:

// wraps a vector. provides convenience conversion constructors
// and assign functions. 
struct bytebuf {
    explicit bytebuf(size_t size):c(size) { }

    template<size_t size>
    bytebuf(char const(&v)[size]) { assign(v); }

    template<size_t size>
    void assign(char const(&v)[size]) {
        c.assign(v, v+size);
    }

    // provide access to wrapped vector
    std::vector<char> & buf() {
        return c;
    }

private:
    std::vector<char> c;
};

int main() {
    bytebuf b("data");
    process(&b.buf()[0], b.buf().size()); // process 5 byte

    std::string str(&b.buf()[0]);
    std::cout << str; // outputs "data"

    bytebuf c(100);
    read(&c.buf()[0], c.buf().size()); // read 100 byte
    // ...
}

There is no need to add many more functions to it, i think. You can always get the vector using buf() and operate on it directly. Since a vectors' storage is contiguous, you can use it like a C array, but it is still resizable:

c.buf().resize(42)

The template conversion constructor and assign function allows you to initialize or assign from a C array directly. If you like, you can add more constructors that can initialize from a set of two iterators or a pointer and a length. But i would try keeping the amount of added functionality low, so it keeps being a tight, transparent vector wrapping struct.

Johannes Schaub - litb
Too many big words. Answer makes my head spin.
Jimmy J
That's just silly! No need to do all that extra work, stop showing off we know you are good ;-)
Martin York
Jimmy J
explicit is not a big word. it's good style to use it. i've used the template to be able to directly pass a C array. i've tried to keep this low. it's not implementing a container requirement even. if he has questions on the template, he is welcome to ask. it's not like i tell him "rtfm"
Johannes Schaub - litb
he's chosen C++. that means he wants to take a hard trip. making c++ look easy when in fact it has myriads of pitfalls (like the unwanted implicit conversions if explicit is not used) won't help him in the long run.
Johannes Schaub - litb
litb - I'm with you on this! :-)
Johann Gerell
You have a compiler in your head.
toto
+2  A: 

If this is C:

unwind
Shouldn't be size_t used in C++ also?
sharptooth
+2  A: 

If you're using the character array as an array of characters, use a std::vector<char> as that's what vectors are for. If you're using the character array as a string, use a std::string which will store its data in pretty much the same way as a std::vector<char>, but will communicate its purpose more clearly.

Max Lybbert
A: 

How are you using your structure?
Is it like an array or like a string?

I would just typedef one of the C++ containers:

typedef  std::string  MyData; // or std::vector<char> if that is more appropriate
Martin York