Strange result

Discussion in 'C++' started by Alf P. Steinbach, Mar 9, 2008.

  1. 1. The program below should theoretically not run on my old & clunky machine,
    since theoretically it allocates 2 to 4 GB. In reality, according to Windows
    Task Manager, it allocates only some 20 MB tops. And runs fine, though slow...

    2. With MSVC, and/or with 10.000 or fewer iterations and Op vector elements, the
    inefficient reference strings are faster than std::string string, as expected.
    On my machine, with g++ and 100.000 iterations, the opposite happens, and the
    machine trashes on allocation and deallocation for the ref strings. I guess on
    a modern machine that limit must be higher (yet another factor of 10?), but I'm
    interested whether (1) this can be reproduced, and (2) whether anyone has any
    explanation (at a guess something causes a lot of memory to be allocated, but it
    doesn't show up in Task Manager).

    Disclaimer: this is late for me, so thinking box not entirely sharp...


    #include <boost/progress.hpp>
    #include <boost/shared_ptr.hpp>
    #include <iostream>
    #include <ostream>
    #include <vector>
    #include <string>

    class RefString
    {
    private:
    boost::shared_ptr<std::string> myString;
    public:
    RefString( size_t n, char c )
    : myString( new std::string( n, c ) )
    {}
    };

    template< class String >
    struct Op_
    {
    String s;
    std::vector<String> v;

    Op_(): s( 200, ' ' ), v( 100, s ) {}
    void operator()() { v.insert( v.begin(), s ); }
    };

    template< class String >
    void doTest()
    {
    using namespace std;
    typedef Op_<String> Op;
    vector<Op> op( 100000 );

    boost::progress_timer timer;
    for( size_t i = 0; i < op.size(); ++i )
    {
    op();
    }
    }

    template< class String >
    void doNamedTest()
    {
    std::cout << typeid(String).name() << ": ";
    doTest<String>();
    }

    int main()
    {
    for( int i = 1; i <= 5; ++i )
    {
    std::cout << "TEST #" << i << ":" << std::endl;
    std::cout << std::endl;

    doNamedTest<RefString>();
    doNamedTest<std::string>();
    }
    }


    Cheers, & TIA.,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Mar 9, 2008
    #1
    1. Advertising

  2. Hi,

    Alf P. Steinbach wrote:

    > 1. The program below should theoretically not run on my old & clunky
    > machine,
    > since theoretically it allocates 2 to 4 GB. In reality, according to
    > Windows
    > Task Manager, it allocates only some 20 MB tops. And runs fine, though
    > slow...
    >
    > 2. With MSVC, and/or with 10.000 or fewer iterations and Op vector
    > elements, the inefficient reference strings are faster than std::string
    > string, as expected. On my machine, with g++ and 100.000 iterations, the
    > opposite happens, and the
    > machine trashes on allocation and deallocation for the ref strings. I
    > guess on a modern machine that limit must be higher (yet another factor of
    > 10?), but I'm interested whether (1) this can be reproduced, and (2)
    > whether anyone has any explanation (at a guess something causes a lot of
    > memory to be allocated, but it doesn't show up in Task Manager).


    I think you're missing copy constructors, see below:

    > Disclaimer: this is late for me, so thinking box not entirely sharp...
    >
    >
    > #include <boost/progress.hpp>
    > #include <boost/shared_ptr.hpp>
    > #include <iostream>
    > #include <ostream>
    > #include <vector>
    > #include <string>
    >
    > class RefString
    > {
    > private:
    > boost::shared_ptr<std::string> myString;
    > public:
    > RefString( size_t n, char c )
    > : myString( new std::string( n, c ) )
    > {}


    // Missing copy constructor for non-PODs:
    RefString(const RefString &s)
    : myString(s.myString)
    { };
    RefString &operator=(const RefString &s)
    { myString = s.myString; return *this; };

    > };
    >
    > template< class String >
    > struct Op_
    > {
    > String s;
    > std::vector<String> v;
    >
    > Op_(): s( 200, ' ' ), v( 100, s ) {}


    // Missing copy constructor for non-PODs:
    Op_(const Op_ &o)
    : s(o.s), v(o.v) { };
    Op_ &operator=(const Op_ &o)
    { s = o.s; v = o.v; return *this; };


    > void operator()() { v.insert( v.begin(), s ); }
    > };
    >
    > template< class String >
    > void doTest()
    > {
    > using namespace std;
    > typedef Op_<String> Op;
    > vector<Op> op( 100000 );
    >
    > boost::progress_timer timer;
    > for( size_t i = 0; i < op.size(); ++i )
    > {
    > op();
    > }
    > }
    >
    > template< class String >
    > void doNamedTest()
    > {
    > std::cout << typeid(String).name() << ": ";
    > doTest<String>();
    > }
    >
    > int main()
    > {
    > for( int i = 1; i <= 5; ++i )
    > {
    > std::cout << "TEST #" << i << ":" << std::endl;
    > std::cout << std::endl;
    >
    > doNamedTest<RefString>();
    > doNamedTest<std::string>();
    > }
    > }


    HTH,
    Paul
    Paul Brettschneider, Mar 9, 2008
    #2
    1. Advertising

  3. * Paul Brettschneider:
    > Hi,
    >
    > Alf P. Steinbach wrote:
    >
    >> 1. The program below should theoretically not run on my old & clunky
    >> machine,
    >> since theoretically it allocates 2 to 4 GB. In reality, according to
    >> Windows
    >> Task Manager, it allocates only some 20 MB tops. And runs fine, though
    >> slow...
    >>
    >> 2. With MSVC, and/or with 10.000 or fewer iterations and Op vector
    >> elements, the inefficient reference strings are faster than std::string
    >> string, as expected. On my machine, with g++ and 100.000 iterations, the
    >> opposite happens, and the
    >> machine trashes on allocation and deallocation for the ref strings. I
    >> guess on a modern machine that limit must be higher (yet another factor of
    >> 10?), but I'm interested whether (1) this can be reproduced, and (2)
    >> whether anyone has any explanation (at a guess something causes a lot of
    >> memory to be allocated, but it doesn't show up in Task Manager).

    >
    > I think you're missing copy constructors, see below:
    >
    >> Disclaimer: this is late for me, so thinking box not entirely sharp...
    >>
    >>
    >> #include <boost/progress.hpp>
    >> #include <boost/shared_ptr.hpp>
    >> #include <iostream>
    >> #include <ostream>
    >> #include <vector>
    >> #include <string>
    >>
    >> class RefString
    >> {
    >> private:
    >> boost::shared_ptr<std::string> myString;
    >> public:
    >> RefString( size_t n, char c )
    >> : myString( new std::string( n, c ) )
    >> {}

    >
    > // Missing copy constructor for non-PODs:
    > RefString(const RefString &s)
    > : myString(s.myString)
    > { };
    > RefString &operator=(const RefString &s)
    > { myString = s.myString; return *this; };


    Nope, these are effectively the same as those generated automatically.


    >> };
    >>
    >> template< class String >
    >> struct Op_
    >> {
    >> String s;
    >> std::vector<String> v;
    >>
    >> Op_(): s( 200, ' ' ), v( 100, s ) {}

    >
    > // Missing copy constructor for non-PODs:
    > Op_(const Op_ &o)
    > : s(o.s), v(o.v) { };
    > Op_ &operator=(const Op_ &o)
    > { s = o.s; v = o.v; return *this; };


    Ditto, no need to reproduce what the language provides automatically.

    Except if there's some bug in g++...


    [snip]
    >
    > HTH,
    > Paul


    Well, it could have. :) So thanks.


    Cheers,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Mar 9, 2008
    #3
  4. On 2008-03-09 09:40, Alf P. Steinbach wrote:
    > 1. The program below should theoretically not run on my old & clunky machine,
    > since theoretically it allocates 2 to 4 GB. In reality, according to Windows
    > Task Manager, it allocates only some 20 MB tops. And runs fine, though slow...


    Task Manager is not the best tool to use when trying to determine how
    much memory an app uses since there are a few different memory-types it
    can show information about. I do not have boost installed but running it
    with the boost-specific parts commented out the app ate about 1.7 GB
    (out of 2 GB available) of RAM, but the total amount allocated was much
    higher (the page-file grew with about 2 GB).

    --
    Erik Wikström
    Erik Wikström, Mar 9, 2008
    #4
  5. Alf P. Steinbach wrote:

    > * Paul Brettschneider:
    >> Hi,
    >>
    >> Alf P. Steinbach wrote:
    >>
    >>> 1. The program below should theoretically not run on my old & clunky
    >>> machine,
    >>> since theoretically it allocates 2 to 4 GB. In reality, according to
    >>> Windows
    >>> Task Manager, it allocates only some 20 MB tops. And runs fine, though
    >>> slow...
    >>>
    >>> 2. With MSVC, and/or with 10.000 or fewer iterations and Op vector
    >>> elements, the inefficient reference strings are faster than std::string
    >>> string, as expected. On my machine, with g++ and 100.000 iterations, the
    >>> opposite happens, and the
    >>> machine trashes on allocation and deallocation for the ref strings. I
    >>> guess on a modern machine that limit must be higher (yet another factor
    >>> of 10?), but I'm interested whether (1) this can be reproduced, and (2)
    >>> whether anyone has any explanation (at a guess something causes a lot of
    >>> memory to be allocated, but it doesn't show up in Task Manager).

    >>
    >> I think you're missing copy constructors, see below:
    >>
    >>> Disclaimer: this is late for me, so thinking box not entirely sharp...
    >>>
    >>>
    >>> #include <boost/progress.hpp>
    >>> #include <boost/shared_ptr.hpp>
    >>> #include <iostream>
    >>> #include <ostream>
    >>> #include <vector>
    >>> #include <string>
    >>>
    >>> class RefString
    >>> {
    >>> private:
    >>> boost::shared_ptr<std::string> myString;
    >>> public:
    >>> RefString( size_t n, char c )
    >>> : myString( new std::string( n, c ) )
    >>> {}

    >>
    >> // Missing copy constructor for non-PODs:
    >> RefString(const RefString &s)
    >> : myString(s.myString)
    >> { };
    >> RefString &operator=(const RefString &s)
    >> { myString = s.myString; return *this; };

    >
    > Nope, these are effectively the same as those generated automatically.


    Ooops, sorry. At least *I* learned something: I used to believe that the
    default copy constructor does a dumb memcpy().

    But the result MSVC vs. g++ is to be expected, isn't it? g++ does use
    refcounting for std::string internally, so adding another refcounting layer
    on top of it should make the program slower/use more memory.
    Paul Brettschneider, Mar 9, 2008
    #5
    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. J.Ram
    Replies:
    7
    Views:
    650
  2. Pavel
    Replies:
    7
    Views:
    526
    Pavel
    Sep 19, 2010
  3. Lakshmi Sreekanth

    i = 10; result = ++i - --i; How result become ZERO

    Lakshmi Sreekanth, Sep 21, 2010, in forum: C Programming
    Replies:
    52
    Views:
    1,175
    Nick Keighley
    Sep 23, 2010
  4. Mr. Buffoon
    Replies:
    4
    Views:
    293
    Eric Sosman
    Sep 23, 2010
  5. Michael Tan
    Replies:
    32
    Views:
    964
    Ara.T.Howard
    Jul 21, 2005
Loading...

Share This Page