Allocating vector of strings seem to crash. Allocating array ofstrings seems to be ok .

Discussion in 'C++' started by Rakesh Kumar, Dec 20, 2007.

  1. Rakesh Kumar

    Rakesh Kumar Guest

    Hi All -
    In a project of mine - I was trying to scale down the actual issue
    to the following piece of code. I need to allocate an array of strings
    and reserve the individual string to a particular size (4K) .
    I wrote 2 functions - allocVectorOfStrings() and
    allocArrayOfStrings().
    Each of them seem to allocate similar amounts of memory - but the
    version of vectorOfStrings seem to crash with the following error -
    "double free or corruption (out): 0x08055ff8 ***" .

    I was just curious if I am doing anything fundamentally wrong here
    to cause the issue.


    #include <iostream>
    #include <cstdlib>
    #include <vector>


    void allocVectorOfStrings();
    void allocArrayOfStrings();

    void allocVectorOfStrings() {
    std::vector<std::string> * vt = new std::vector<std::string>();
    vt->reserve(50);
    for (size_t i = 0; i < vt->capacity(); ++i) {
    std::cout << "We are probably ok" << i << "\n";
    vt->operator[](i).reserve(40);
    }
    delete vt;
    }

    void allocArrayOfStrings() {
    std::string * vt = new std::string[4096];
    for (size_t i = 0; i < 1024; ++i) {
    std::cout << "We are probably ok" << i << "\n";
    vt.reserve(4096);
    }
    delete [] vt;
    }

    int main()
    {
    allocArrayOfStrings();
    allocVectorOfStrings(); //This function crashes
    return EXIT_SUCCESS;
    }
    Rakesh Kumar, Dec 20, 2007
    #1
    1. Advertising

  2. Re: Allocating vector of strings seem to crash. Allocating array of strings seems to be ok .

    Rakesh Kumar wrote:
    > Hi All -
    > In a project of mine - I was trying to scale down the actual issue
    > to the following piece of code. I need to allocate an array of strings
    > and reserve the individual string to a particular size (4K) .
    > I wrote 2 functions - allocVectorOfStrings() and
    > allocArrayOfStrings().
    > Each of them seem to allocate similar amounts of memory - but the
    > version of vectorOfStrings seem to crash with the following error -
    > "double free or corruption (out): 0x08055ff8 ***" .
    >
    > I was just curious if I am doing anything fundamentally wrong here
    > to cause the issue.
    >
    >
    > #include <iostream>
    > #include <cstdlib>
    > #include <vector>
    >
    >
    > void allocVectorOfStrings();
    > void allocArrayOfStrings();
    >
    > void allocVectorOfStrings() {
    > std::vector<std::string> * vt = new std::vector<std::string>();
    > vt->reserve(50);


    'reserve' does not construct vector's elements. It only allocates
    memory for constructing them later, when 'insert' is used. Here
    '*vt' does not contain _any strings_. It's empty. It's _capable_
    of containing at least 50 without reallocation of its storage. But
    it doesn't have any elements.

    > for (size_t i = 0; i < vt->capacity(); ++i) {


    This is a very bad idea. Never iterate to capacity. Always
    iterate to size.

    > std::cout << "We are probably ok" << i << "\n";


    No, you're not OK.

    > vt->operator[](i).reserve(40);


    You're accessing a non-existent element at the index 'i' and
    then calls a member functions for it. Undefined behaviour.

    > }
    > delete vt;
    > }
    >
    > void allocArrayOfStrings() {
    > std::string * vt = new std::string[4096];


    Here 'vt' contains all 4096 elements.

    > for (size_t i = 0; i < 1024; ++i) {
    > std::cout << "We are probably ok" << i << "\n";


    Yes, you are.

    > vt.reserve(4096);


    'vt' represents a real string. You can call 'reserve' for
    it, no problem.

    > }
    > delete [] vt;
    > }
    >
    > int main()
    > {
    > allocArrayOfStrings();
    > allocVectorOfStrings(); //This function crashes
    > return EXIT_SUCCESS;
    > }


    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Dec 20, 2007
    #2
    1. Advertising

  3. Rakesh Kumar

    Salt_Peter Guest

    On Dec 20, 11:10 am, Rakesh Kumar <> wrote:
    > Hi All -
    > In a project of mine - I was trying to scale down the actual issue
    > to the following piece of code. I need to allocate an array of strings
    > and reserve the individual string to a particular size (4K) .
    > I wrote 2 functions - allocVectorOfStrings() and
    > allocArrayOfStrings().
    > Each of them seem to allocate similar amounts of memory - but the
    > version of vectorOfStrings seem to crash with the following error -
    > "double free or corruption (out): 0x08055ff8 ***" .
    >
    > I was just curious if I am doing anything fundamentally wrong here
    > to cause the issue.
    >
    > #include <iostream>
    > #include <cstdlib>
    > #include <vector>
    >
    > void allocVectorOfStrings();
    > void allocArrayOfStrings();
    >
    > void allocVectorOfStrings() {
    > std::vector<std::string> * vt = new std::vector<std::string>();
    > vt->reserve(50);
    > for (size_t i = 0; i < vt->capacity(); ++i) {
    > std::cout << "We are probably ok" << i << "\n";
    > vt->operator[](i).reserve(40);


    Try not to use new / delete unless you are required to do so.
    You are attempting to access an element that doesn't yet exist.
    reserve constructs nothing.
    use vector's member function at(...) when in doubt. see below.

    > }
    > delete vt;
    >
    > }
    >
    > void allocArrayOfStrings() {
    > std::string * vt = new std::string[4096];
    > for (size_t i = 0; i < 1024; ++i) {
    > std::cout << "We are probably ok" << i << "\n";
    > vt.reserve(4096);
    > }
    > delete [] vt;
    >
    > }
    >
    > int main()
    > {
    > allocArrayOfStrings();
    > allocVectorOfStrings(); //This function crashes
    > return EXIT_SUCCESS;
    >
    > }


    #include <iostream>
    #include <string>
    #include <vector>
    #include <stdexcept>

    void allocVectorOfStrings()
    {
    std::vector<std::string> vt(10, "default string");
    std::cout << "vt's size is " << vt.size() << std::endl;
    for(size_t i = 0; i < vt.size(); ++i)
    {
    std::cout << "vt[ " << i << " ] ";
    std::cout << vt.at(i) << std::endl;
    }
    // uncomment for a test
    // vt.at(10) = "out or range";
    }

    int main()
    {
    try
    {
    allocVectorOfStrings();
    }
    catch( const std::exception& e)
    {
    std::cout << "Error:";
    std::cout << e.what() << std::endl;
    }
    }

    /*
    vt's size is 10
    vt[ 0 ] default string
    ....
    vt[ 9 ] default string
    */
    Salt_Peter, Dec 20, 2007
    #3
  4. Rakesh Kumar

    Rakesh Kumar Guest

    On Dec 20, 8:17 am, "Victor Bazarov" <> wrote:
    > Rakesh Kumar wrote:
    > > Hi All -
    > > In a project of mine - I was trying to scale down the actual issue
    > > to the following piece of code. I need to allocate an array of strings
    > > and reserve the individual string to a particular size (4K) .
    > > I wrote 2 functions - allocVectorOfStrings() and
    > > allocArrayOfStrings().
    > > Each of them seem to allocate similar amounts of memory - but the
    > > version of vectorOfStrings seem to crash with the following error -
    > > "double free or corruption (out): 0x08055ff8 ***" .

    >
    > > I was just curious if I am doing anything fundamentally wrong here
    > > to cause the issue.

    >
    > > #include <iostream>
    > > #include <cstdlib>
    > > #include <vector>

    >
    > > void allocVectorOfStrings();
    > > void allocArrayOfStrings();

    >
    > > void allocVectorOfStrings() {
    > > std::vector<std::string> * vt = new std::vector<std::string>();
    > > vt->reserve(50);

    >
    > 'reserve' does not construct vector's elements. It only allocates
    > memory for constructing them later, when 'insert' is used. Here
    > '*vt' does not contain _any strings_. It's empty. It's _capable_
    > of containing at least 50 without reallocation of its storage. But
    > it doesn't have any elements.
    >
    > > for (size_t i = 0; i < vt->capacity(); ++i) {

    >
    > This is a very bad idea. Never iterate to capacity. Always
    > iterate to size.
    >
    > > std::cout << "We are probably ok" << i << "\n";

    >
    > No, you're not OK.
    >
    > > vt->operator[](i).reserve(40);

    >
    > You're accessing a non-existent element at the index 'i' and
    > then calls a member functions for it. Undefined behaviour.


    Thanks Victor.
    The revised function seems to do what I intended in the first place.

    void allocVectorOfStrings()
    {
    std::vector<std::string> vt(1024);

    for (size_t i = 0; i < vt.size(); ++i)
    {
    std::cout << "Vector seems to be ok too" << i << "\n";
    vt.reserve(4096);
    }
    }

    Just a quick question - after a vector is allocated - is there a way I
    can mass construct elements at one shot (instead of using insert /
    push_back ) - similar to the construct shown above.




    >
    > > }
    > > delete vt;
    > > }

    >
    > > void allocArrayOfStrings() {
    > > std::string * vt = new std::string[4096];

    >
    > Here 'vt' contains all 4096 elements.
    >
    > > for (size_t i = 0; i < 1024; ++i) {
    > > std::cout << "We are probably ok" << i << "\n";

    >
    > Yes, you are.
    >
    > > vt.reserve(4096);

    >
    > 'vt' represents a real string. You can call 'reserve' for
    > it, no problem.
    >
    > > }
    > > delete [] vt;
    > > }

    >
    > > int main()
    > > {
    > > allocArrayOfStrings();
    > > allocVectorOfStrings(); //This function crashes
    > > return EXIT_SUCCESS;
    > > }

    >
    > V
    > --
    > Please remove capital 'A's when replying by e-mail
    > I do not respond to top-posted replies, please don't ask
    Rakesh Kumar, Dec 20, 2007
    #4
  5. Rakesh Kumar

    werasm Guest

    On Dec 20, 6:56 pm, Rakesh Kumar <> wrote:
    > On Dec 20, 8:17 am, "Victor Bazarov" <> wrote:
    >
    >
    >
    > > Rakesh Kumar wrote:
    > > > Hi All -
    > > > In a project of mine - I was trying to scale down the actual issue
    > > > to the following piece of code. I need to allocate an array of strings
    > > > and reserve the individual string to a particular size (4K) .
    > > > I wrote 2 functions - allocVectorOfStrings() and
    > > > allocArrayOfStrings().
    > > > Each of them seem to allocate similar amounts of memory - but the
    > > > version of vectorOfStrings seem to crash with the following error -
    > > > "double free or corruption (out): 0x08055ff8 ***" .

    >
    > > > I was just curious if I am doing anything fundamentally wrong here
    > > > to cause the issue.

    >
    > > > #include <iostream>
    > > > #include <cstdlib>
    > > > #include <vector>

    >
    > > > void allocVectorOfStrings();
    > > > void allocArrayOfStrings();

    >
    > > > void allocVectorOfStrings() {
    > > > std::vector<std::string> * vt = new std::vector<std::string>();
    > > > vt->reserve(50);

    >
    > > 'reserve' does not construct vector's elements. It only allocates
    > > memory for constructing them later, when 'insert' is used. Here
    > > '*vt' does not contain _any strings_. It's empty. It's _capable_
    > > of containing at least 50 without reallocation of its storage. But
    > > it doesn't have any elements.

    >
    > > > for (size_t i = 0; i < vt->capacity(); ++i) {

    >
    > > This is a very bad idea. Never iterate to capacity. Always
    > > iterate to size.

    >
    > > > std::cout << "We are probably ok" << i << "\n";

    >
    > > No, you're not OK.

    >
    > > > vt->operator[](i).reserve(40);

    >
    > > You're accessing a non-existent element at the index 'i' and
    > > then calls a member functions for it. Undefined behaviour.

    >
    > Thanks Victor.
    > The revised function seems to do what I intended in the first place.
    >
    > void allocVectorOfStrings()
    > {
    > std::vector<std::string> vt(1024);
    >
    > for (size_t i = 0; i < vt.size(); ++i)
    > {
    > std::cout << "Vector seems to be ok too" << i << "\n";
    > vt.reserve(4096);
    > }
    >
    > }
    >
    > Just a quick question - after a vector is allocated - is there a way I
    > can mass construct elements at one shot (instead of using insert /
    > push_back ) - similar to the construct shown above.


    vt.resize( x );

    After resize is used the vector will contain x elements. You could
    also re-assign to it or use swap e.g:

    vt = std::vector<std::string>( x ); //or

    std::vector<std::string> v( x )
    vt.swap( v );

    I think resize would most probably be the best option though.

    Regards,

    Werner
    werasm, Dec 20, 2007
    #5
  6. Rakesh Kumar

    James Kanze Guest

    On Dec 20, 6:56 pm, Rakesh Kumar <> wrote:
    > On Dec 20, 8:17 am, "Victor Bazarov" <> wrote:
    > > Rakesh Kumar wrote:
    > > > In a project of mine - I was trying to scale down the actual issue
    > > > to the following piece of code. I need to allocate an array of strings
    > > > and reserve the individual string to a particular size (4K) .
    > > > I wrote 2 functions - allocVectorOfStrings() and
    > > > allocArrayOfStrings().
    > > > Each of them seem to allocate similar amounts of memory - but the
    > > > version of vectorOfStrings seem to crash with the following error -
    > > > "double free or corruption (out): 0x08055ff8 ***" .


    > > > I was just curious if I am doing anything fundamentally wrong here
    > > > to cause the issue.


    > > > #include <iostream>
    > > > #include <cstdlib>
    > > > #include <vector>


    > > > void allocVectorOfStrings();
    > > > void allocArrayOfStrings();


    > > > void allocVectorOfStrings() {
    > > > std::vector<std::string> * vt = new std::vector<std::string>();
    > > > vt->reserve(50);


    > > 'reserve' does not construct vector's elements. It only allocates
    > > memory for constructing them later, when 'insert' is used. Here
    > > '*vt' does not contain _any strings_. It's empty. It's _capable_
    > > of containing at least 50 without reallocation of its storage. But
    > > it doesn't have any elements.


    > > > for (size_t i = 0; i < vt->capacity(); ++i) {


    > > This is a very bad idea. Never iterate to capacity. Always
    > > iterate to size.


    > > > std::cout << "We are probably ok" << i << "\n";


    > > No, you're not OK.


    > > > vt->operator[](i).reserve(40);


    > > You're accessing a non-existent element at the index 'i' and
    > > then calls a member functions for it. Undefined behaviour.


    Still, a good implementation of the library will output a more
    or less sensible error message when you do it. I get:
    error: attempt to subscript container with out-of-bounds index 0,
    but
    container only holds 0 elements.
    when I try it with g++, for example (provided I've activated
    debugging, but I always do). And VC++ indicates "Expression:
    vector subscript out of range" in its pop-up box. Rather clear
    as well.

    > Thanks Victor.
    > The revised function seems to do what I intended in the first place.


    > void allocVectorOfStrings()
    > {
    > std::vector<std::string> vt(1024);


    > for (size_t i = 0; i < vt.size(); ++i)
    > {
    > std::cout << "Vector seems to be ok too" << i << "\n";
    > vt.reserve(4096);
    > }
    > }


    > Just a quick question - after a vector is allocated - is there
    > a way I can mass construct elements at one shot (instead of
    > using insert / push_back ) - similar to the construct shown
    > above.


    In the above, the elements are mass constructed, in the
    constructor of vt. In this case, they are copy constructed from
    the default, std::string(), but you can pass any initial value
    you want, and they will be copy constructed from that.

    On the other hand, the capacity() is not part of the "value" of
    a string, and is not necessarily copied by the copy constructor;
    in order to ensure the capacity of all of the elements, I think
    you do have to do something like the above. Alternatively, you
    could do:

    std::vector< std::string > vt(
    1024,
    std::string( 4096, '\0') ) ;

    , which will ensure the actual size (and not just the capacity).

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Dec 21, 2007
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. pmatos
    Replies:
    6
    Views:
    23,700
  2. Replies:
    5
    Views:
    240
    Anthra Norell
    Sep 4, 2006
  3. Replies:
    8
    Views:
    1,873
    Csaba
    Feb 18, 2006
  4. Javier
    Replies:
    2
    Views:
    532
    James Kanze
    Sep 4, 2007
  5. Phi!
    Replies:
    1
    Views:
    162
Loading...

Share This Page