复制在我的 string::copy 实现中不起作用

Posted

技术标签:

【中文标题】复制在我的 string::copy 实现中不起作用【英文标题】:Copy doesn't work in my string::copy implementation 【发布时间】:2016-04-21 18:55:08 【问题描述】:

跟进https://codereview.stackexchange.com/q/126242/23788。

我写了我的字符串类,根据反馈我改变了一些东西。还有什么需要修复的吗?

+operator 不起作用,我不知道我做错了什么。执行“Str+Str”时出现段错误。

Process finished with exit code 139

这是我的 Str.h

class Str 

    friend std::istream &operator>>(std::istream &, Str &);

    friend void swap(Str &s, Str &t) 
        std::swap(s.data, t.data);
        std::swap(s.length, t.length);
        std::swap(s.alloc, t.alloc);
    


public:
    typedef char *iterator;
    typedef size_t size_type;

    Str() : data(nullptr), length(0), capacity(0)  

    Str(size_type length, char char_to_fill) : Str()  create(length, char_to_fill); 

    Str(const char *s) : Str()  create(s); 

    template<class In>
    Str(In b, In e) : Str()  create(b, e); 

    ~Str() 
        if (data) alloc.deallocate(data, capacity);
        data = nullptr;
    

    Str(const Str &s) 
        *this = s;
    

    // move constructor?
    Str(Str &&other)
            : Str() // initialize via default constructor, C++11 only
        swap(*this, other);
    

    Str &operator+=(const Str &s) 
        size_type new_length = length + s.length - 1; //remove 1 because of 2 nulls
        if (new_length > capacity) 
            reallocate(new_length);
            strcpy(data + length - 1, s.data); //overwrite null from s
            length = new_length;
        
        else //if there was already enough space
            strcpy(data + length - 1, s.data);
        
        return *this;
    

    Str &operator=(Str rhs) 
        swap(*this, rhs);
        return *this;
    

    char &operator[](size_type i)  return data[i]; ;

    const char &operator[](size_type i) const  return data[i]; ;

    size_type size()  return length; 

    const size_type size() const  return length; 

    const char *c_str() const 
        return data;
    

    void copy(char *dest, size_type n) 
        if (n > length)
            throw std::out_of_range("Out of range");
        std::copy(data, data + n, dest);
    

    char *begin()  return data; ;

    char *end()  return data + length; ;

    void push_back(char c) 
        if (length == capacity) 
            reallocate(capacity == 0 ? DEFAULT_CAPACITY : 2 * capacity);
        
        data[length++] = c;
    

private:
    char *data;
    std::allocator<char> alloc;
    size_type length;
    size_type capacity;
    static const size_type DEFAULT_CAPACITY = 20;

    void create(size_type n, char character_to_fill) 
        capacity = length = n + 1;
        data = alloc.allocate(capacity);
        std::uninitialized_fill(data, data + length - 1, character_to_fill);
        //alloc.construct(data + length - 1, '\0'); //is it needed to be constructed?
        data[length - 1] = '\0';
    

    void create(const char *s) 
        capacity = length = strlen(s) + 1;
        data = alloc.allocate(capacity);
        strcpy(data, s);
        //alloc.construct(data + length - 1, '\0');
        data[length - 1] = '\0';
    

    template<class In>
    void create(In b, In e) 
        capacity = e - b + 1;
        data = alloc.allocate(capacity);
        while (b != e) 
            data[length++] = *(b++);
        
        //alloc.construct(data + length -1, '\0');
        data[length++] = '\0';
    

    void reallocate(size_t new_capacity) 
        char *new_data = alloc.allocate(new_capacity);
        std::copy(data, data + length, new_data);
        alloc.deallocate(data, length);
        data = new_data;
        capacity = new_capacity;
    
;

std::istream &operator>>(std::istream &is, Str &s) 
    std::vector<char> buf;
    char actual_character;
    while (is.get(actual_character) && isspace(actual_character))  ;
    
    if (is)  //is it correct to check "is" ?
        do buf.push_back(actual_character);
        while (is.get(actual_character) && !isspace(actual_character));
        if (is)
            is.unget();
    
    s.create(buf.begin(), buf.end());
    return is;


std::ostream &operator<<(std::ostream &os, const Str &s) 
    os << s.c_str();
    return os;


Str operator+(Str lhs, const Str &rhs) 
    lhs += rhs;
    return lhs;

还有例子 main.cpp

#include <iostream>
#include <vector>
#include "Str.h"

using std::cout;
using std::endl;

int main() 
    Str s("Siema");
    cout<<s.c_str()<<endl;

    s = "Hello";
    cout<<s<<endl;

    s.push_back('a');
    cout<<s<<endl;

    Str t = "World";
    //cout<<s+t<<endl; //THIS DOESNT WORK

    s+=t;
    cout<<s<<endl;

    cout<<s[3]<<s[5]<<s[11]<<endl;

    cout<<s.size()<<endl;
    cout<<Str(s.begin()+3, s.end()-2)<<endl;
    for(Str::iterator i = s.begin(); i<s.end() ; i+=2)
        cout<<i<<endl;
    

    char copied[3];
    t.copy(copied, 4);
    cout<<copied<<endl;

    return 0;

【问题讨论】:

代码审查和堆栈溢出对于什么是格式良好的问题有非常不同的标准;请阅读minimal reproducible example 和How to Ask。 可能重复:***.com/questions/36364191/… 为什么你的拷贝构造函数调用赋值运算符,它调用拷贝构造函数(参数传值),它调用赋值运算符,它调用拷贝构造函数...?对我来说似乎是一个无限循环。您的复制构造函数应该在没有赋值运算符的帮助下编写。那么在赋值运算符中就可以使用copy/swap了。 【参考方案1】:

在您的代码中

char copied[3];
t.copy(copied, 4);
cout<<copied<<endl;

“已复制”只有 3 个长度,而您尝试将 4 个字符复制到其中。这会导致问题

检查下面的更新代码。用 " 读取 cmets

str.h

#include <iostream>
#include <memory>
#include <vector>
class Str 

friend std::istream &operator >> (std::istream &, Str &);

 void swap(Str &s, Str &t) 
    std::swap(s.data, t.data);
    std::swap(s.length, t.length);
    std::swap(s.alloc, t.alloc);



public:
typedef char *iterator;
typedef size_t size_type;

Str() : data(nullptr), length(0), capacity(0)  

Str(size_type length, char char_to_fill) : Str()  create(length, char_to_fill); 

Str(const char *s) : Str()  create(s); 

template<class In>
Str(In b, In e) : Str()  create(b, e); 

~Str() 
    if (data) alloc.deallocate(data, capacity);
    data = nullptr;


Str(const Str &s) 
    *this = s;


// move constructor?
Str(Str &&other)
    : Str() // initialize via default constructor, C++11 only
    swap(*this, other);


Str &operator+=(const Str &s) 
    size_type new_length = length + s.length - 1; //remove 1 because of 2 nulls
    if (new_length > capacity) 
        reallocate(new_length);
        strcpy(data + length - 1, s.data); //overwrite null from s
        //length = new_length;  //<-- You need to update the length anyay. Move it to before return
    
    else //if there was already enough space
        strcpy(data + length - 1, s.data);
    
    length = new_length; //<-- update the length
    return *this;


Str &operator=(Str rhs) 
    swap(*this, rhs);
    return *this;


char &operator[](size_type i)  return data[i]; ;

const char &operator[](size_type i) const  return data[i]; ;

size_type size()  return length; 

const size_type size() const  return length; 

const char *c_str() const 
    return data;


void copy(char *dest, size_type n) 
    if (n > length)
        throw std::out_of_range("Out of range");
    std::copy(data, data + n, dest);  // <--forgot about '\0'?
    dest[n] = '\0';                   // <-- add '\0'


char *begin()  return data; ;

char *end()  return data + length; ;

void push_back(char c) 
    if (length == capacity) 
        reallocate(capacity == 0 ? DEFAULT_CAPACITY : 2 * capacity);
    
    data[length++ - 1] = c;  //<-- length - 1 is the last position, because length here includes '\0'
    data[length - 1] = 0;    //<-- don't forget to add '\0'. It's better if you fill the unused spaces to '\0' after allocate them.


private:
char *data;
std::allocator<char> alloc;
size_type length;
size_type capacity;
static const size_type DEFAULT_CAPACITY = 20;

void create(size_type n, char character_to_fill) 
    capacity = length = n + 1;
    data = alloc.allocate(capacity);
    std::uninitialized_fill(data, data + length - 1, character_to_fill);
    //alloc.construct(data + length - 1, '\0'); //is it needed to be constructed?
    data[length - 1] = '\0';


void create(const char *s) 
    capacity = length = strlen(s) + 1;
    data = alloc.allocate(capacity);
    strcpy(data, s);
    //alloc.construct(data + length - 1, '\0');
    data[length - 1] = '\0';


template<class In>
void create(In b, In e) 
    capacity = e - b + 1;
    data = alloc.allocate(capacity);
    while (b != e) 
        data[length++] = *(b++);
    
    //alloc.construct(data + length -1, '\0');
    data[length++] = '\0';


void reallocate(size_t new_capacity) 
    char *new_data = alloc.allocate(new_capacity);
    std::copy(data, data + length, new_data);
    alloc.deallocate(data, length);
    data = new_data;
    capacity = new_capacity;

;

std::istream &operator >> (std::istream &is, Str &s) 
std::vector<char> buf;
char actual_character;
while (is.get(actual_character) && isspace(actual_character)) 
    ;

if (is)  //is it correct to check "is" ?
    do buf.push_back(actual_character);
    while (is.get(actual_character) && !isspace(actual_character));
    if (is)
        is.unget();

s.create(buf.begin(), buf.end());
return is;


std::ostream &operator<<(std::ostream &os, const Str &s) 
os << s.c_str();
return os;


Str operator+(Str lhs, const Str &rhs) 
lhs += rhs;
return lhs;

和主要的:

int main() 
Str s("Siema");
cout << s.c_str() << endl;

s = "Hello";
cout << s << endl;

s.push_back('a');
cout << s << endl;

Str t = "World";
//cout<<s+t<<endl; //THIS DOESNT WORK

s += t;
cout << s << endl;

cout << s[3] << s[5] << s[11] << endl;

cout << s.size() << endl;
cout << Str(s.begin() + 3, s.end() - 2) << endl;
for (Str::iterator i = s.begin(); i<s.end(); i += 2) 
    cout << i << endl;


char copied[5];  //<-- was 3, not enough space
t.copy(copied, 4);
cout << copied << endl;

return 0;

【讨论】:

以上是关于复制在我的 string::copy 实现中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

插件在 CodeIgniter 中不起作用

模态在我的网络服务器中不起作用,但在 localhost 中起作用。这是为啥?

AngularJS、SweetAlert.js 在自定义指令中不起作用

为啥我的刷新验证码在 Firefox 中不起作用? [复制]

发布在构建定义 VS2012 中不起作用

导出到 CSV/Excel 功能在 Datatable 中不起作用?