void str_vec::reallocate() { auto new_capacity = size()>1?size()*2:1; auto new_data = alloc.allocate(new_capacity); auto dest = new_data; auto elem = elements; for(std::size_t i = 0;i<size();++i) alloc.construct(dest++,std::move(*elem++)); free(); elements = new_data; first_free = dest; std::cout << cap - elements << std::endl; cap = new_data+new_capacity; }
/** * @brief allocate memory for spicified number of elements * @param n * @note it's user's responsibility to ensure that @param n is greater than * the current capacity. */ void StrVec::wy_alloc_n_move(std::size_t n) { std::size_t newCapacity = n; std::string* newData = alloc.allocate(newCapacity); std::string* dest = newData; std::string* elem = element; //! move the old to newly allocated space. for (std::size_t i = 0; i != size(); ++i) alloc.construct(dest++, std::move(*elem++)); free(); //! update data structure element = newData; first_free = dest; cap = element + newCapacity; }
/** * @brief allocate new room if nessary and push back the new string * @param s new string */ void StrVec::push_back(const std::string& s) { chk_n_alloc(); alloc.construct(first_free++, s); }
void reallocate() { auto newcap = size() ? size()*2 : 1; auto newspace = alloc.allocate(newcap); std::cout << "reallocate: size() " << size() << std::endl; auto dest = newspace; auto source = element_; // move the data from the old memory to the new // std::move() returns rvalue, which cause construct() to use string // move ctor. // // seg-fault when have a typo and use element in the loop: // // for (size_t i = 0; i != size(); ++i) // alloc.construct(dest++, std::move(*element_++)); // // *gdb-debug* bt when use -g // Program terminated with signal SIGSEGV, Segmentation fault. // #0 0x00007f94aa120113 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string&&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 // (gdb) bt // #0 0x00007f94aa120113 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string&&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 // #1 0x0000000000401bf7 in __gnu_cxx::new_allocator<std::string>::construct<std::string<std::string> > (this=0x602cd1 <StrVec::alloc>, __p=0xa53000) at /usr/include/c++/4.9/ext/new_allocator.h:120 // #2 0x0000000000401932 in StrVec::reallocate (this=0x7ffdc9026bc0) at t_ex_strvec.cpp:117 // #3 0x0000000000401aa5 in StrVec::check_and_alloc (this=0x7ffdc9026bc0) at t_ex_strvec.cpp:147 // #4 0x000000000040165e in StrVec::push_back (this=0x7ffdc9026bc0, s="two") at t_ex_strvec.cpp:44 // #5 0x000000000040133e in main () at t_ex_strvec.cpp:198 // // when not use -g // (gdb) bt // #0 0x00007f3348f5c113 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string&&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 // #1 0x0000000000401bf7 in void __gnu_cxx::new_allocator<std::string>::construct<std::string, std::string>(std::string*, std::string&&) () // #2 0x0000000000401932 in StrVec::reallocate() () // #3 0x0000000000401aa5 in StrVec::check_and_alloc() () // #4 0x000000000040165e in StrVec::push_back(std::string const&) () // #5 0x000000000040133e in main () // // How to debug? See that uses 'construct' and gdb is useful to see // what's going on when stepping through. Found out that the loop // continues and saw that when add to print i and size(). // // ... // i: 16856, size: 18446744073709534761 // Segmentation fault (core dumped) // // (gdb) f 2 // #2 0x0000000000401932 in StrVec::reallocate (this=0x7ffdc9026bc0) at t_ex_strvec.cpp:117 // 117 alloc.construct(dest++, std::move(*element_++)); // (gdb) p i // $1 = 16856 // (gdb) p/u free_-element_ // $6 = 18446744073709534760 // // Why? Since element_ is member data and keep increasing it, then // size() member function would produce negative which turns into // big number sicne size() returns size_t, unsigned int. for (size_t i = 0; i != size(); ++i) { // std::cout << "i: " << i << ", size: " << size() << std::endl; alloc.construct(dest++, std::move(*source++)); } // std::cout.flush(); // std::this_thread::sleep_for(std::chrono::seconds{5}); // to point the new space element_ = newspace; free_ = dest; cap_ = element_ + newcap; }