【问题标题】:Error returning a list of user-defined objects from a function in C++从 C++ 中的函数返回用户定义对象列表时出错
【发布时间】:2014-07-26 23:25:28
【问题描述】:

背景

出于教学目的,我编写了一个模拟字符串操作的类StrStr 类本质上是一个字符数组。

我创建了一个函数makeList,它接收一个Str 对象,使用push_back 创建一个Str 对象列表并返回该列表。

我正在使用allocators,但我已加强内存管理,只为创建的字符分配足够的内存。

问题

  • 编译、链接和运行时不会产生错误。

  • 使用cout << ret.back()MakeList 中查看列表对象内容正常。

  • 问题在于,在main 正文中查看时,列表中的对象的垃圾输入覆盖了前约 10 个字符。

  • 我还验证了我创建的 Str 正在通过默认析构函数被销毁。

我已经包含了复制问题的最少代码量。

非类代码:

list<Str> makeList(const Str s)
    {
        list<Str> ret;
        ret.push_back(s);
        cout << ret.back() << endl;

        return ret;
    }

    int main() {

        Str greeting = "Hello world";
        list<Str> result;
        result = makeList(greeting);
        result.pop_front();
        cout << "The result is " << result.front() << endl;

        return 0;
    }

类代码:

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

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

    Str(const_iterator cp, const_iterator cp2) {
        create(cp, cp2);
    }
    Str(const_iterator cp) {
        create(cp, cp + strlen(cp));
    }
    ~Str() {uncreate(); }

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

    Str& operator=(const Str& s) {
        uncreate();
        create(s.begin(), s.end());
    };

    Str substr(size_type i, size_type d) const {
        const_iterator cStart, cTerm;
        cStart = this->begin() + i;
        cTerm  = this->begin() + i + d;
        Str sub(cStart, cTerm);
        cout << "Pointer diff = " << sub.limit - sub.data << endl;
        return sub;
    }

    size_type size() const { return avail - data; }

    iterator begin() { return data; }
    const_iterator begin() const { return data; }

    iterator end() { return avail; }
    const_iterator end() const { return avail; }


private:
    iterator data;
    iterator avail;
    iterator limit;

    allocator<char> alloc;

    void create();
    void create(const_iterator, const_iterator);

    void uncreate();

};

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

void Str::create(const_iterator i, const_iterator j)
{
    data = alloc.allocate(j - i);
    limit = avail = uninitialized_copy(i, j, data);
}

void Str::uncreate()
{
    if (data) {
        iterator it = avail;
        while (it != data)
            alloc.destroy(--it);

        alloc.deallocate(data, limit - data);
    }

    data = limit = avail = 0;
    cout << "UNCREATED" << endl;
}

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

}

【问题讨论】:

  • 那么,复制/移动构造函数在哪里?它被称为例如list&lt;Str&gt;::push_back 编译器生成的不会做你想做的事(浅拷贝)。请遵循三规则(C++11 中的五规则)或零规则。
  • 谢谢。这或许可以解释。我在线阅读了 push_back 操作的文档,但无法从用户定义的对象中找到它所需的内容。我不确定这是不是问题,因为 push_back 操作使用 makeList 函数中的 cout 创建了一个明显合适的列表。
  • 我正在使用的教科书 AcceleratedC++,总体来说非常好,但在它的原始 Str 定义中也没有复制构造函数。

标签: c++ list memory-management allocator


【解决方案1】:

除其他外,您缺少Str 的复制构造函数,但您确实在此处调用它:

 result2 = makeList(greeting); // Pass by value -> copy

这里:

 ret.push_back(s);  // Pass by value -> copy

没有它,将使用默认的复制构造函数,但它并没有做你想做的事。 可能的实现:

Str(const Str& other) 
{
    create(other.begin(), other.end());
}

永远尊重the rule of three

【讨论】:

  • 按值传递的Str 调用复制ctor。
  • 一会儿,我没有意识到make_list 中的list :) -- 在 C++11 中,这将使用 list 的移动赋值运算符,AFAIK .
猜你喜欢
  • 2019-09-11
  • 2012-08-17
  • 2019-12-30
  • 1970-01-01
  • 2021-08-09
  • 2021-09-16
  • 2021-09-28
  • 1970-01-01
  • 2020-03-01
相关资源
最近更新 更多