2012-11-26 68 views
2

作爲Accelerated C++問題12.1的一部分,我正在執行一個字符串類的實現。這主要是這個構造:segfault對字符串數組的轉換

Str(const char* cp) { 
    std::copy(cp, cp+std::strlen(cp), std::back_inserter(*this)); 
} 

,這似乎是造成問題的時候back_inserter調用push_back

void Str::push_back(const char& c){ 
    if ((data + length) == limit){ 
     grow(); 
    } 
    unchecked_append(c); 
} 

這似乎導致在調用grow()但在執行任何的grow()身體的問題之前。

void Str::grow() 
{ 
    // when growing, allocate twice as much space as currently in use 
    size_type new_size = std::max(2 * (limit - data), ptrdiff_t(1)); 
    // allocate new space and copy existing elements to the new space 
    iterator new_data = alloc.allocate(new_size); 
    iterator new_avail = std::uninitialized_copy(data, (data+length), new_data); 

    // return the old space 
    uncreate(); 
    // reset pointers to point to the newly allocated space 
    data = new_data; 
    limit = data + new_size; 
} 

具體來說,它會導致Windows說「Str.exe已停止工作」,並導致Ubuntu報告分段錯誤。

這裏是我的完整代碼:

#ifndef _GUARD_STR_H 
#define _GUARD_STR_H 

#include <ctype.h> 
#include <memory> 
#include <iterator> 
#include <iostream> 
#include <cstddef> 
#include <cstring> 

class Str { 
    friend std::istream& operator>>(std::istream&, Str&); 
    public: 
     typedef size_t size_type; 
     typedef char * iterator; 
     typedef const char * const_iterator; 
     typedef char& reference; 
     typedef const char& const_reference; 
     typedef char value_type; 

     Str& operator+=(const Str& s){ 
      std::copy(s.begin(), s.end(), 
      std::back_inserter(*this)); 
      return *this; 
     } 

     // default constructor; create an empty Str 
     Str() { create();} 

     // create a Str containing n copies of c 
     Str(size_type n, char c){ } 

     iterator end() { return data + length; } 
     iterator begin() { return data; } 
     const_iterator end() const { return data + length; } 
     const_iterator begin() const { return data; } 

     // create a Str from a null-terminated array of char 
     Str(const char* cp) { 
      std::copy(cp, cp+std::strlen(cp), std::back_inserter(*this)); 
     } 

     template<class In> Str(In i, In j) { 
      std::copy(i, j, std::back_inserter(data)); 
     } 

     std::allocator<char> alloc; 

     void push_back(const char&); 

     char& operator[](size_type i) { return data[i]; } 
     const char& operator[](size_type i) const { return data[i]; } 
     size_type size() const { return length; } 

    private: 
     iterator data; 
     size_t length; 
     iterator limit; 
     void create(); 
     void create(size_type, char); 
     void grow(); 
     void unchecked_append(const char& c); 
     void uncreate(); 
}; 

void Str::push_back(const char& c){ 
    if ((data + length) == limit){ 
     grow(); 
    } 
    unchecked_append(c); 
} 

void Str::unchecked_append(const char & val) 
{ 
    alloc.construct((data+(length++)), val); 
} 

void Str::uncreate() 
{ 
    if (data) { 
     // destroy (in reverse order) the elements that were constructed 
     iterator it = (data + length); 
     while (it != data) 
      alloc.destroy(--it); 

     // return all the space that was allocated 
     alloc.deallocate(data, limit - data); 
    } 

    // reset pointers to indicate that the Vec is empty again 
    data = limit = 0; 
} 

void Str::create(){ 
    data = limit = 0; 
} 

void Str::create(size_type n, char c){ 
    data = alloc.allocate(n); 
    std::uninitialized_fill(data, data + n, c); 
} 

void Str::grow() 
{ 
    // when growing, allocate twice as much space as currently in use 
    size_type new_size = std::max(2 * (limit - data), ptrdiff_t(1)); 
    // allocate new space and copy existing elements to the new space 
    iterator new_data = alloc.allocate(new_size); 
    iterator new_avail = std::uninitialized_copy(data, (data+length), new_data); 

    // return the old space 
    uncreate(); 
    // reset pointers to point to the newly allocated space 
    data = new_data; 
    limit = data + new_size; 
} 

std::ostream& operator<<(std::ostream&, const Str&); 
Str operator+(const Str&, const Str&); 

std::ostream& operator<<(std::ostream& os, const Str& s) 
{ 
    for (Str::size_type i = 0; i != s.size(); ++i) 
     os << s[i]; 
    return os; 
} 

std::istream& operator>>(std::istream& is, Str& s) 
{ 
    char c; 
    while (is.get(c)){ 
     s.push_back(c); 
    } 
    return is; 
} 

Str operator+(const Str& s, const Str& t) 
{ 
    Str r = s; 
    r += t; 
    return r; 
} 

#endif 

是什麼造成分段錯誤?

+1

你試過調試器嗎?程序崩潰了嗎? –

回答

3

您似乎並未在任何地方初始化length

+2

+1,實際上,此代碼中的長度永遠不會分配*任何位置*,包括增長和副本中的長度,但會重複評估 – WhozCraig