Thread: Vectro clear function

  1. #1
    Registered User
    Join Date
    Nov 2019
    Posts
    14

    Vectro clear function

    Hi guys, Im using library of STL called #include <vector>
    when I have a vector like this:
    Code:
     vector<int> v
    I do push_back(10) 10times, then I do v.clear() then if I do v.size() then it will return zero... what's confusing is how PC can know that we have cleared the vector and it's size is zero?! because it's really complicated to imagine it.. could anyone help me how can PC clear the values of vector and update that the size of vector is zero?!

    what's confusing me that Im not accepting that idea in freshy way that PC can after cleaning the vector will return zero .. it's like human thinking but how does he do that? really weird .. is it maybe system call to do clear for data?!
    Last edited by Brian_Teir; 12-09-2019 at 12:59 PM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    37,736
    I guess the fun exercise is to try writing your own version of vector.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Dec 2017
    Posts
    860
    It probably just sets the size member to 0. Try this. It prints 3 for me, even though the vector was "cleared".
    Code:
    #include <iostream>
    #include <vector>
     
    int main() {
        std::vector<int> v;
        for (int i = 0; i < 10; ++i)
            v.push_back(i);
        v.clear();
        std::cout << v[3] << '\n';
    }
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

  4. #4
    Registered User
    Join Date
    Aug 2019
    Location
    Inside a Singularity
    Posts
    253
    Why are you trying to find out what your PC knows or doesn't know? When you are learning programming languages, you don't question how your computer is able to do something. You should focus more on learning the language more than trying to think what's happening in the background. Eventually, when you've studied enough, you'll realise that your PC is nothing but a stupid device that can perform just simple math operations and move things from one location in memory to another.

    When you clear the vector, it gets rid of all the heap allocated memory and sets its inner size to 0. You'll understand better once you've covered OOP. For now, stop diving into thought experiments about what the PC/Computer/Compiler/Interpreter/CPU do and focus more on the important aspects of the language. There is so much that happens in the background that it'd just be a bad experience if you don't focus on the language and instead pay attention to low level implementation details directly.

    This is the pseudo-representation/disassembly of what your computer understands based on the above code you described:

    Code:
    0x401350    lea    0x4(%esp),%ecx
    0x401354    and    $0xfffffff0,%esp
    0x401357    pushl  -0x4(%ecx)
    0x40135a    push   %ebp
    0x40135b    mov    %esp,%ebp
    0x40135d    push   %edi
    0x40135e    push   %esi
    0x40135f    push   %ebx
    0x401360    push   %ecx
    0x401361    sub    $0x68,%esp
    0x401364    movl   $0x401880,-0x44(%ebp)
    0x40136b    movl   $0x4b67c0,-0x40(%ebp)
    0x401372    lea    -0x3c(%ebp),%eax
    0x401375    lea    -0x18(%ebp),%ebx
    0x401378    mov    %ebx,(%eax)
    0x40137a    mov    $0x4013f6,%edx
    0x40137f    mov    %edx,0x4(%eax)
    0x401382    mov    %esp,0x8(%eax)
    0x401385    lea    -0x5c(%ebp),%eax
    0x401388    mov    %eax,(%esp)
    0x40138b    call   0x4279c0 <_Unwind_SjLj_Register>
    0x401390    call   0x427150 <__main>
    0x401395    lea    -0x24(%ebp),%eax
    0x401398    mov    %eax,%ecx
    0x40139a    call   0x4a20cc <std::vector<int, std::allocator<int> >::vector()>
    0x40139f    movl   $0x0,-0x28(%ebp)
    0x4013a6    mov    -0x28(%ebp),%eax
    0x4013a9    cmp    $0x9,%eax
    0x4013ac    jg     0x4013d3 <main()+131>
    0x4013ae    lea    -0x24(%ebp),%eax
    0x4013b1    lea    -0x28(%ebp),%edx
    0x4013b4    mov    %edx,(%esp)
    0x4013b7    movl   $0x1,-0x58(%ebp)
    0x4013be    mov    %eax,%ecx
    0x4013c0    call   0x4a206c <std::vector<int, std::allocator<int> >::push_back(int const&)>
    0x4013c5    sub    $0x4,%esp
    0x4013c8    mov    -0x28(%ebp),%eax
    0x4013cb    add    $0x1,%eax
    0x4013ce    mov    %eax,-0x28(%ebp)
    0x4013d1    jmp    0x4013a6 <main()+86>
    0x4013d3    lea    -0x24(%ebp),%eax
    0x4013d6    mov    %eax,%ecx
    0x4013d8    call   0x4a2048 <std::vector<int, std::allocator<int> >::clear()>
    0x4013dd    movl   $0x0,-0x60(%ebp)
    0x4013e4    lea    -0x24(%ebp),%eax
    0x4013e7    mov    %eax,%ecx
    0x4013e9    call   0x4a2110 <std::vector<int, std::allocator<int> >::~vector()>
    0x4013ee    mov    -0x60(%ebp),%eax
    0x4013f1    mov    %eax,-0x60(%ebp)
    0x4013f4    jmp    0x40141b <main()+203>
    0x4013f6    lea    0x18(%ebp),%ebp
    0x4013f9    mov    -0x54(%ebp),%eax
    0x4013fc    mov    %eax,-0x60(%ebp)
    0x4013ff    lea    -0x24(%ebp),%eax
    0x401402    mov    %eax,%ecx
    0x401404    call   0x4a2110 <std::vector<int, std::allocator<int> >::~vector()>
    0x401409    mov    -0x60(%ebp),%eax
    0x40140c    mov    %eax,(%esp)
    0x40140f    movl   $0xffffffff,-0x58(%ebp)
    0x401416    call   0x428020 <_Unwind_SjLj_Resume>
    0x40141b    lea    -0x5c(%ebp),%eax
    0x40141e    mov    %eax,(%esp)
    0x401421    call   0x427b20 <_Unwind_SjLj_Unregister>
    0x401426    mov    -0x60(%ebp),%eax
    0x401429    lea    -0x10(%ebp),%esp
    0x40142c    pop    %ecx
    0x40142d    pop    %ebx
    0x40142e    pop    %esi
    0x40142f    pop    %edi
    0x401430    pop    %ebp
    0x401431    lea    -0x4(%ecx),%esp
    0x401434    ret
    A slightly more readable version:
    Code:
    ;4  :    {
    0x401350    lea    0x4(%esp),%ecx
    0x401354    and    $0xfffffff0,%esp
    0x401357    pushl  -0x4(%ecx)
    0x40135a    push   %ebp
    0x40135b    mov    %esp,%ebp
    0x40135d    push   %edi
    0x40135e    push   %esi
    0x40135f    push   %ebx
    0x401360    push   %ecx
    0x401361    sub    $0x68,%esp
    0x401364    movl   $0x401880,-0x44(%ebp)
    0x40136b    movl   $0x4b67c0,-0x40(%ebp)
    0x401372    lea    -0x3c(%ebp),%eax
    0x401375    lea    -0x18(%ebp),%ebx
    0x401378    mov    %ebx,(%eax)
    0x40137a    mov    $0x4013f6,%edx
    0x40137f    mov    %edx,0x4(%eax)
    0x401382    mov    %esp,0x8(%eax)
    0x401385    lea    -0x5c(%ebp),%eax
    0x401388    mov    %eax,(%esp)
    0x40138b    call   0x4279c0 <_Unwind_SjLj_Register>
    0x401390    call   0x427150 <__main>
    ;5  :        std::vector <int> v;
    0x401395    lea    -0x24(%ebp),%eax
    0x401398    mov    %eax,%ecx
    0x40139a    call   0x4a20cc <std::vector<int, std::allocator<int> >::vector()>
    0x4013e4    lea    -0x24(%ebp),%eax
    0x4013e7    mov    %eax,%ecx
    0x4013e9    call   0x4a2110 <std::vector<int, std::allocator<int> >::~vector()>
    0x4013ee    mov    -0x60(%ebp),%eax
    0x4013f1    mov    %eax,-0x60(%ebp)
    0x4013f4    jmp    0x40141b <main()+203>
    0x4013f6    lea    0x18(%ebp),%ebp
    0x4013f9    mov    -0x54(%ebp),%eax
    0x4013fc    mov    %eax,-0x60(%ebp)
    0x4013ff    lea    -0x24(%ebp),%eax
    0x401402    mov    %eax,%ecx
    0x401404    call   0x4a2110 <std::vector<int, std::allocator<int> >::~vector()>
    0x401409    mov    -0x60(%ebp),%eax
    0x40140c    mov    %eax,(%esp)
    0x40140f    movl   $0xffffffff,-0x58(%ebp)
    0x401416    call   0x428020 <_Unwind_SjLj_Resume>
    0x40141b    lea    -0x5c(%ebp),%eax
    0x40141e    mov    %eax,(%esp)
    0x401421    call   0x427b20 <_Unwind_SjLj_Unregister>
    ;7  :        for (int i = 0; i < 10; i++)
    0x40139f    movl   $0x0,-0x28(%ebp)
    0x4013a6    mov    -0x28(%ebp),%eax
    0x4013a9    cmp    $0x9,%eax
    0x4013ac    jg     0x4013d3 <main()+131>
    0x4013c8    mov    -0x28(%ebp),%eax
    0x4013cb    add    $0x1,%eax
    0x4013ce    mov    %eax,-0x28(%ebp)
    0x4013d1    jmp    0x4013a6 <main()+86>
    ;8  :            v.push_back(i);
    0x4013ae    lea    -0x24(%ebp),%eax
    0x4013b1    lea    -0x28(%ebp),%edx
    0x4013b4    mov    %edx,(%esp)
    0x4013b7    movl   $0x1,-0x58(%ebp)
    0x4013be    mov    %eax,%ecx
    0x4013c0    call   0x4a206c <std::vector<int, std::allocator<int> >::push_back(int const&)>
    0x4013c5    sub    $0x4,%esp
    ;10 :        v.clear ();
    0x4013d3    lea    -0x24(%ebp),%eax
    0x4013d6    mov    %eax,%ecx
    0x4013d8    call   0x4a2048 <std::vector<int, std::allocator<int> >::clear()>
    ;12 :        return 0;
    0x4013dd    movl   $0x0,-0x60(%ebp)
    ;13 :    }
    0x401426    mov    -0x60(%ebp),%eax
    0x401429    lea    -0x10(%ebp),%esp
    0x40142c    pop    %ecx
    0x40142d    pop    %ebx
    0x40142e    pop    %esi
    0x40142f    pop    %edi
    0x401430    pop    %ebp
    0x401431    lea    -0x4(%ecx),%esp
    0x401434    ret
    This is for the code:
    Code:
    #include <bits/stdc++.h>
    
    int main (void)
    {
        std::vector <int> v;
    
        for (int i = 0; i < 10; i++)
            v.push_back(i);
    
        v.clear ();
    
        return 0;
    }
    As you can notice, your PC doesn't know anything. It's just a stupid machine that can do simple math operations and move things around and jump through memory locations using complex circuitry. It's you, the programmer, that makes it do cool things by exploiting these simple facts. And to be a good programmer, learning the language aspect is more important, at first, than figuring out "how PC can know" things.
    Last edited by Zeus_; 12-09-2019 at 01:52 PM.
    "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." - Rick Cook, The Wizardry Compiled

  5. #5
    Registered User
    Join Date
    Dec 2017
    Posts
    860
    Quote Originally Posted by Zeus_
    When you clear the vector, it gets rid of all the heap allocated memory
    No it doesn't. That was my point.
    Although I could've made it better by printing the capacity after the clear().
    Last edited by john.c; 12-09-2019 at 01:53 PM.
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

  6. #6
    Registered User
    Join Date
    Aug 2019
    Location
    Inside a Singularity
    Posts
    253
    Thanks, I thought so though. So, does that mean that it just re-writes over the already allocated memory? Cuz if that's so, then it's probably a brilliant idea.
    "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." - Rick Cook, The Wizardry Compiled

  7. #7
    Registered User
    Join Date
    Dec 2017
    Posts
    860
    Quote Originally Posted by Zeus_ View Post
    So, does that mean that it just re-writes over the already allocated memory?
    Exactly. There's the shrink_to_fit() method for actually returning memory back to the allocator (although it probably won't return it back to the operating system, since that's pretty much pointless).
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

  8. #8
    Registered User
    Join Date
    May 2019
    Posts
    214
    Quote Originally Posted by Zeus_ View Post
    Thanks, I thought so though. So, does that mean that it just re-writes over the already allocated memory? Cuz if that's so, then it's probably a brilliant idea.
    Yes. Actually part of the point of vector is exactly that, along with dynamic allocation when required (though there are lots of points to be made about that with respect to performance).

    The vector dynamically allocates some room for some entries of the appropriate type. At the "beginning" the count is zero, but the capacity is usually higher.

    As you push, the count is incremented until the capacity is exhausted. At that point the vector will re-allocate storage to expand it (if a push would be beyond capacity).

    When you clear, or erase elements, the count is decremented (or set to zero). The storage may not be cleared, but there are rules entirely up to the implementation (compilers behave differently on this point). If, for example, the vector held hundreds of thousands of entries and you call clear, it may be wise to reduce the allocation to a lower volume rather than "waste" all of that space. On the other hand, if the volume were, say, 10, then it makes no sense to release that memory, assuming the vector will have new entries pushed into it soon.

    That said, you may also find "reserve" interesting, because it allows the programmer to set the capacity to a large-ish allocated space for performance reasons.

  9. #9
    Registered User
    Join Date
    Aug 2019
    Location
    Inside a Singularity
    Posts
    253
    Oh, cool! The STL just got more interesting to me. It's a brilliant solution tbh and yeah, I always wondered why the capacity was not 0 when I learnt vector for the first time. Makes a lot more sense now thinking of the optimisation strategies. Yeah, reserve is cool. Thanks for the explanation!
    "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." - Rick Cook, The Wizardry Compiled

  10. #10
    Registered User
    Join Date
    Nov 2019
    Posts
    14
    Thanks alot guys!

  11. #11
    Registered User
    Join Date
    Dec 2017
    Posts
    860
    If you stored a million ints in a vector and then cleared it, it would be pretty arbitrary for the system to "deallocate" the memory since, as far as it knows, you may be about to fill it up again with another million ints. That's why shrink_to_fit() was added in C++11, so the programmer, who actually knows what he's going to do, can shrink it if he desires.

    Here's my results (gcc) :
    Code:
    #include <iostream>
    #include <vector>
     
    int main() {
        std::vector<int> v;
        std::cout << "cap1: " << v.capacity() << '\n'; // 0
        for (int i = 0; i < 1000000; ++i)
            v.push_back(i);
        std::cout << "cap2: " << v.capacity() << '\n';  // 1048576
        v.clear();
        std::cout << "cap3: " << v.capacity() << '\n';  // 1048576
        v.shrink_to_fit();
        std::cout << "cap4: " << v.capacity() << '\n';  // 0
    }
    reserve() is always a good idea if you know you are going to be creating a large vector. Again, it's the programmer who knows what's best here.
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,547
    Quote Originally Posted by john.c
    It probably just sets the size member to 0.
    It has to destroy the elements too, though in this case for int it isn't really relevant.

    Quote Originally Posted by john.c
    Although I could've made it better by printing the capacity after the clear().
    And avoided the possibility of running into an assert on some implementation, methinks

    Quote Originally Posted by john.c
    There's the shrink_to_fit() method for actually returning memory back to the allocator (although it probably won't return it back to the operating system, since that's pretty much pointless).
    shrink_to_fit is non-binding, i.e., the implementation is not required to actually shrink to fit, so the old technique of swapping with an empty temporary vector would still apply if you really want to shrink a zero size vector to fit, though in this day and age I guess move assignment would be the way to go since it should be as simple as:
    Code:
    x = std::vector();
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Registered User
    Join Date
    Dec 2017
    Posts
    860
    Great points. I forgot all about the destructor calls (when appropriate) and the non-binding nature of shrink_to_fit(). Just goes to show how memory management is pretty complicated.
    Thanks laserlight!
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Clear screen function
    By Brolaf Broski in forum C Programming
    Replies: 10
    Last Post: 11-13-2013, 04:02 PM
  2. A function to Clear String.
    By sergioms in forum C Programming
    Replies: 4
    Last Post: 11-22-2008, 01:02 PM
  3. clear screen function
    By mrprogrmr in forum C Programming
    Replies: 16
    Last Post: 12-28-2004, 10:49 AM
  4. clear screen function
    By monkeymon in forum C Programming
    Replies: 6
    Last Post: 10-05-2002, 12:23 PM
  5. Is there any clear function?
    By lockpatrick in forum C Programming
    Replies: 9
    Last Post: 03-27-2002, 09:07 AM

Tags for this Thread