当前位置:  开发笔记 > 编程语言 > 正文

在C++中的类初始值设定项中初始化const数组

如何解决《在C++中的类初始值设定项中初始化const数组》经验,为你挑选了5个好方法。

我在C++中有以下类:

class a {
    const int b[2];
    // other stuff follows

    // and here's the constructor
    a(void);
}

问题是,如何在初始化列表中初始化b,因为我无法在构造函数体内初始化它,因为b是const

这不起作用:

a::a(void) : 
    b([2,3])
{
     // other initialization stuff
}

编辑:这个例子就是我可以b为不同的实例设置不同的值,但是已知这些值在实例的生命周期内是不变的.



1> Flexo..:

使用C++ 11,这个问题的答案现在已经改变了,你实际上可以做到:

struct a {
    const int b[2];
    // other bits follow

    // and here's the constructor
    a();
};

a::a() :
    b{2,3}
{
     // other constructor work
}

int main() {
 a a;
}



2> Weipeng L..:

像其他人说的那样,ISO C++不支持这一点.但你可以解决它.只需使用std :: vector.

int* a = new int[N];
// fill a

class C {
  const std::vector v;
public:
  C():v(a, a+N) {}
};


这个问题是它使用导致额外开销的向量.

3> Luc Touraill..:

目前的标准是不可能的.我相信你能够做到这一点的C++ 0x使用初始化列表(见在的C++ 0x略看,由Bjarne Stroustrup的,有关初始化列表和其他不错的C++ 0x功能的更多信息).



4> 小智..:

std::vector使用堆.Geez,这只是为了进行const理智检查而浪费的东西.重点std::vector是运行时的动态增长,而不是应该在编译时进行的任何旧的语法检查.如果你不想增长,那么创建一个类来包装一个普通的数组.

#include 


template 
class ConstFixedSizeArrayFiller {
private:
    size_t length;

public:
    ConstFixedSizeArrayFiller() : length(0) {
    }

    virtual ~ConstFixedSizeArrayFiller() {
    }

    virtual void Fill(Type *array) = 0;

protected:
    void add_element(Type *array, const Type & element)
    {
        if(length >= MaxLength) {
            // todo: throw more appropriate out-of-bounds exception
            throw 0;
        }
        array[length] = element;
        length++;
    }
};


template 
class ConstFixedSizeArray {
private:
    Type array[Length];

public:
    explicit ConstFixedSizeArray(
        ConstFixedSizeArrayFiller & filler
    ) {
        filler.Fill(array);
    }

    const Type *Array() const {
        return array;
    }

    size_t ArrayLength() const {
        return Length;
    }
};


class a {
private:
    class b_filler : public ConstFixedSizeArrayFiller {
    public:
        virtual ~b_filler() {
        }

        virtual void Fill(int *array) {
            add_element(array, 87);
            add_element(array, 96);
        }
    };

    const ConstFixedSizeArray b;

public:
    a(void) : b(b_filler()) {
    }

    void print_items() {
        size_t i;
        for(i = 0; i < b.ArrayLength(); i++)
        {
            printf("%d\n", b.Array()[i]);
        }
    }
};


int main()
{
    a x;
    x.print_items();
    return 0;
}

ConstFixedSizeArrayFiller并且ConstFixedSizeArray可以重复使用.

第一个允许在初始化数组时进行运行时边界检查(与向量相同),稍后可以const在此初始化之后进行.

第二个允许将数组分配另一个对象中,该对象可以在堆上,或者只是堆栈(如果该对象所在的位置).从堆中分配时不浪费时间.它还对数组执行编译时const检查.

b_filler是一个提供初始化值的微小私有类.使用模板参数在编译时检查数组的大小,因此不可能超出范围.

我敢肯定有更多奇特的方法可以修改它.这是一个初步的刺.我认为你几乎可以弥补任何编译器的类缺点.


它在堆上有什么关系?无论是在堆还是堆栈上,内存都将在对象的整个生命周期中使用.考虑到许多架构在相同的内存块的相对侧具有堆和堆栈,因此它们理论上可以在中间相遇,为什么对象所在的位置很重要?
@Nathan Fellman:这可能被视为过度优化,但在某些情况下,您希望您的对象进行零分配(在堆栈上使用).在这种情况下,"new"太多了,如果你在编译时知道你需要多少,那就更多了.例如,std :: vector的一些实现确实在内部缓冲区中分配它的项目,而不是使用"new",使得构造/销毁的小向量非常便宜.

5> orj..:

ISO标准C++不允许您这样做.如果是这样,语法可能是:

a::a(void) :
b({2,3})
{
    // other initialization stuff
}

或类似的规定.从你的问题来看,它实际上听起来像你想要的是一个常数类(又名静态)成员,即数组.C++确实允许你这样做.像这样:

#include 

class A 
{
public:
    A();
    static const int a[2];
};

const int A::a[2] = {0, 1};

A::A()
{
}

int main (int argc, char * const argv[]) 
{
    std::cout << "A::a => " << A::a[0] << ", " << A::a[1] << "\n";
    return 0;
}

输出是:

A::a => 0, 1

当然,因为这是一个静态类成员,它对于类A的每个实例都是相同的.如果那不是你想要的,即你希望A的每个实例在数组中都有不同的元素值,那么你就是在做尝试使数组const开始的错误.你应该这样做:

#include 

class A 
{
public:
    A();
    int a[2];
};

A::A()
{
    a[0] = 9; // or some calculation
    a[1] = 10; // or some calculation
}

int main (int argc, char * const argv[]) 
{
    A v;
    std::cout << "v.a => " << v.a[0] << ", " << v.a[1] << "\n";
    return 0;
}

推荐阅读
家具销售_903
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有