【问题标题】:how a vector of objects (with static members) is constructed如何构造对象向量(具有静态成员)
【发布时间】:2011-10-18 20:26:39
【问题描述】:

我编写了以下代码来测试具有静态成员的对象向量。我希望输出是:

1 2 3 4 5
6 7 8 9 10

但实际输出是:

1 2 3 4 5
6 6 6 6 6

看起来静态成员没有按预期增加。谁能解释一下?

// ==== test.h =====
using namespace std;

void test();

class Record{
    static int total_number;
    int id;
public: 
    Record();
    void show() {std::cout << id << " "; }
};


// ==== test.cpp ====
#include "stdafx.h"
#include <iostream>
#include <vector>
#include "test.h"
using namespace std;

Record::Record(){
    total_number += 1;
    id = total_number;
 }

void test(){

    const int vec_length = 5;
    Record a[vec_length];

    for (unsigned int i=0; i<vec_length; i++)
        a[i].show();

    cout << endl;    

    vector<Record> vr(vec_length);
    for (unsigned int i=0; i<vr.size(); i++)
        vr[i].show();
    cout << endl;
}


// ==== main.cpp =====
#include "stdafx.h"
#include <iostream>
#include "test.h"
using namespace std;

int Record::total_number = 0;

int _tmain(int argc, _TCHAR* argv[])
{
    test();
    return 0;
}

【问题讨论】:

  • Record::Record()的定义在哪里?
  • 看看复制构造函数的威力...

标签: c++ stl static vector constructor


【解决方案1】:

在 C++98/03 中,你的向量是用这个构造函数初始化的:

std::vector<Record> v(5, Record());

这将创建一个新对象,增加静态变量,然后将该变量的五个副本 来填充元素。总共有 1 个默认构造和 5 个复制构造,产生 6 6 6 6 6

在 C++11 中,构造函数是:

std::vector<Record> v(5);

这会为五个元素创建空间并对它们进行值初始化,这对于您的类型意味着默认构造函数为每个元素调用一次。总共有五个默认构造,产生6 7 8 9 10

【讨论】:

    【解决方案2】:

    我猜你对Record::Record 的定义是这样的

    Record::Record() : id(++total_number) {}
    

    并且您希望vector&lt;Record&gt; 构造函数只调用该构造函数。但是,vector 只执行一次,然后通过编译器生成的复制构造函数复制其余部分,如下所示:

    Record::Record(const Record &other) : id(other.id) {}
    

    你也必须覆盖它。

    【讨论】:

    • 查看我的代码我必须询问我的默认构造函数版本是否是有效的 C++。
    • @Mooing :从技术上讲,id 甚至在进入构造函数主体之前就被初始化,因为它是在构造函数的初始化列表中初始化的。
    • @ildjarn:在 OPs 代码中,它在正文开始时未初始化。当我解释他的评论时,我认为 krynr 是 OP :(
    • @Mooing :啊,我明白了,抱歉不必要的更正。 :-]
    【解决方案3】:

    vector&lt;Record&gt; vr(vec_length); 有点松散。我假设您会期待 vec_length 默认构造调用,但另一种可行的实现是创建一个默认构造对象,然后创建 vec_length-1 副本。也就是说,您未能提供适当的复制构造函数。

    【讨论】:

    • 对于完全符合标准指定行为的情况,这是一个有点混乱的答案......尽管答案取决于语言标准!
    【解决方案4】:

    我建议(在没有完整代码的情况下,我假设在 Record::Record() 中您执行 ++total_number)问题就在这里

    向量 vr(vec_length);

    用 vec_length 记录初始化 std::vector。

    std::vector 要求它的类型是可复制构造的,即你必须实现 Record::Record(const Record&)。发生的事情是这样的:因为 std::vector 没有 Record(),它通过构造它来创建一个(调用 Record::Record(),它将总计数增加到 6)。然后使用刚刚创建的实例调用 Record::Record(const Record&) 复制剩余的 vec_length-1 记录。

    由于您还没有提供一个 copy-ctor,编译器为您创建了一个,它只是简单地按位复制对象。由于 vec_length 对类来说是静态的,因此不会复制任何内容 - 而且由于 copy-ctor 不会增加静态值,因此不会发生任何事情(即简单地保留该值)。

    所以这些的输出是 6。

    【讨论】:

      【解决方案5】:

      你使用的向量构造函数的定义如下:

      显式向量 ( size_type n, const T& value= T(), const Allocator& = Allocator() ); 重复序列构造函数:初始化向量,并将其内容设置为重复 n 次值的副本。这是link to the man page

      我相信这意味着向量构造函数将运行一次默认构造函数(导致 6 次),然后再运行 4 次复制构造函数(导致更多 6 次)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-07-16
        • 1970-01-01
        • 1970-01-01
        • 2013-02-05
        • 2020-07-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多