【问题标题】:C++ curious behavior in vector::push_back()vector::push_back() 中的 C++ 奇怪行为
【发布时间】:2011-05-12 07:19:26
【问题描述】:

我有以下数据结构作为名为“Task”的类:

private:
string name;
int computation_time;
int period;

此外,我还有一个包含此内容的 ASCII 文件:

A 3 10
B 2 12
C 1 11

name = A,computation_time = 3,period = 10 等等......

现在我想读入文件,创建任务对象并将其推回向量中:

void read_in_task_list_and_create_tasks(const string &filename, vector<Task> &current_tasks)
{
    ifstream in_file;
    in_file.open(filename.c_str());

    string tmp_name;
    int tmp_computation_time;
    int tmp_period;

    while(!in_file.eof())
    {
        in_file >> tmp_name;
        in_file >> tmp_computation_time;
        in_file >> tmp_period;

//        Task tmp_task(tmp_name, tmp_computation_time, tmp_period);
//        current_tasks.push_back(tmp_task);
        current_tasks.push_back(Task(tmp_name, tmp_computation_time, tmp_period));
    }
}

现在,当我查看 current_tasks 向量时,它有元素,但它们的值与我的 in_file 值不匹配。 观看注释掉的行。 tmp_task 对象是完全正确的,但如果它被推回,它就会失去上面描述的值。

这可能是任务类中的复制构造函数问题,因为 std::vector 正在管理内存分配吗?

我在 Linux x86 上使用带有 g++ 编译器的 netbeans。

谢谢

【问题讨论】:

  • 你能发布Task类的完整定义吗?

标签: c++ vector push-back


【解决方案1】:

确保没有定义复制构造函数或赋值运算符。

自动的应该做你想要的。

【讨论】:

    【解决方案2】:

    至少 IMO,您采取了一些错误的方法,试图自己做太多的工作。标准库已经可以处理您正在做的大部分事情。您真正需要做的就是指定如何从流中读取单个对象:

    struct Task { 
        std::string name;
        int computation_time;
        int period;
    };
    
    std::istream &operator>>(std::istream &is, Task &t) {
        return is >> t.name >> t.computation_time >> t.period;
    }
    

    然后您可以使用标准算法来实际读取数据并将其放入您的向量中:

    void read_in_task_list_and_create_tasks(const string &filename, 
                                            vector<Task> &current_tasks) 
    {
        std::ifstream in(filename.c_str());
    
        std::copy(std::istream_iterator<Task>(in), 
                  std::istream_iterator<Task>(),
                  std::back_inserter(current_tasks));
    }
    

    作为奖励,这也将解决您似乎两次读取文件中的最后一项的问题,因为您的循环错误(是的,我知道您没有提到这一点,但基于您编写循环,这基本上是不可避免的)。

    【讨论】:

    • 好吧,我没有这个问题,因为我的文件不以换行符结尾,但无论如何,这是完成这些事情的一种非常快速和简单的方法!
    • +1,很好地使用了 STL 算法。我为您修正了istream_iterator 的拼写错误。
    【解决方案3】:

    Task 是否定义了复制构造函数和赋值运算符?当您将对象推入向量时,它并没有将那个确切的对象推入,而是在复制它。因此,我相信您需要定义其中一个(我不记得是哪个,但如果您定义任何一个,最好同时定义两者)。

    【讨论】:

    • 默认的复制构造函数应该对给定的成员做正确的事情。当然,如果 Askener 声明了他自己的复制构造函数,他需要确保它有效。
    • @Askener,该复制构造函数是正确的签名,但这也意味着它取代了正常的编译器生成的默认值,这将完成成员的简单复制。 Netbeans 提供的复制构造函数存根不会对成员数据进行任何复制,以便解释您所看到的行为。在这种情况下,由于您没有分配自己的内存,因此您可以删除 Netbeans 生成的复制构造函数(以及赋值操作符,如果它有的话)
    • @Herms - 如果您定义其中 1 个,则应同时定义这两个。三巨头法则:en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
    • @ orip - 如果我在我的类中使用 new 或分配指针分配内存,我只会定义复制构造函数。当属性在堆栈上分配时,我通常不会这样做
    • @beldaz:是的,元素被移动而不是被复制,所以(例如)std::vector&lt;std::unique_ptr&gt; 应该可以正常工作(即使你不能复制unique_ptr)。
    猜你喜欢
    • 1970-01-01
    • 2020-06-25
    • 2011-03-06
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    相关资源
    最近更新 更多