在 C++ 中的类初始值设定项中初始化一个常量数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/161790/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:22:33  来源:igfitidea点击:

initialize a const array in a class initializer in C++

c++initializationc++03array-initialize

提问by Nathan Fellman

I have the following class in C++:

我在 C++ 中有以下类:

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

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

The question is, how do I initialize b in the initialization list, given that I can't initialize it inside the body of the function of the constructor, because b is const?

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

This doesn't work:

这不起作用:

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

Edit: The case in point is when I can have different values for bfor different instances, but the values are known to be constant for the lifetime of the instance.

编辑:恰当的例子是我可以b为不同的实例设置不同的值,但已知这些值在实例的生命周期内是恒定的。

采纳答案by Weipeng L

Like the others said, ISO C++ doesn't support that. But you can workaround it. Just use std::vector instead.

就像其他人说的那样,ISO C++ 不支持。但是你可以解决它。只需使用 std::vector 代替。

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

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

回答by Flexo

With C++11 the answer to this question has now changed and you can in fact do:

有了 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;
}

回答by Luc Touraille

It is not possible in the current standard. I believe you'll be able to do this in C++0x using initializer lists (see A Brief Look at C++0x, by Bjarne Stroustrup, for more information about initializer lists and other nice C++0x features).

在当前的标准中是不可能的。我相信您将能够使用初始化列表在 C++0x 中执行此操作(请参阅Bjarne Stroustrup 的A Brief Look at C++0x,了解有关初始化列表和其他不错的 C++0x 功能的更多信息)。

回答by Matthew

std::vectoruses the heap. Geez, what a waste that would be just for the sake of a constsanity-check. The point of std::vectoris dynamic growth at run-time, not any old syntax checking that should be done at compile-time. If you're not going to grow then create a class to wrap a normal array.

std::vector使用堆。天哪,为了const健全检查而浪费,真是太浪费了。重点std::vector是运行时的动态增长,而不是任何应该在编译时进行的旧语法检查。如果您不打算增长,则创建一个类来包装普通数组。

#include <stdio.h>


template <class Type, size_t MaxLength>
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 Type, size_t Length>
class ConstFixedSizeArray {
private:
    Type array[Length];

public:
    explicit ConstFixedSizeArray(
        ConstFixedSizeArrayFiller<Type, Length> & filler
    ) {
        filler.Fill(array);
    }

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

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


class a {
private:
    class b_filler : public ConstFixedSizeArrayFiller<int, 2> {
    public:
        virtual ~b_filler() {
        }

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

    const ConstFixedSizeArray<int, 2> 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;
}

ConstFixedSizeArrayFillerand ConstFixedSizeArrayare reusable.

ConstFixedSizeArrayFiller并且ConstFixedSizeArray可以重复使用。

The first allows run-time bounds checking while initializing the array (same as a vector might), which can later become constafter this initialization.

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

The second allows the array to be allocated insideanother object, which could be on the heap or simply the stack if that's where the object is. There's no waste of time allocating from the heap. It also performs compile-time const checking on the array.

第二个允许将数组分配另一个对象内,如果对象所在的位置,则该对象可以在堆上或简单地在堆栈上。从堆分配不会浪费时间。它还对数组执行编译时常量检查。

b_filleris a tiny private class to provide the initialization values. The size of the array is checked at compile-time with the template arguments, so there's no chance of going out of bounds.

b_filler是一个提供初始化值的小型私有类。在编译时使用模板参数检查数组的大小,因此不会越界。

I'm sure there are more exotic ways to modify this. This is an initial stab. I think you can pretty much make up for any of the compiler's shortcoming with classes.

我确信有更多奇特的方法来修改它。这是一个初步的刺。我认为你可以用类来弥补编译器的任何缺点。

回答by orj

ISO standard C++ doesn't let you do this. If it did, the syntax would probably be:

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

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

Or something along those lines. From your question it actually sounds like what you want is a constant class (aka static) member that is the array. C++ does let you do this. Like so:

或类似的规定。从您的问题来看,实际上听起来您想要的是作为数组的常量类(又名静态)成员。C++ 确实让你这样做。像这样:

#include <iostream>

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;
}

The output being:

输出为:

A::a => 0, 1

Now of course since this is a static class member it is the same for every instance of class A. If that is not what you want, ie you want each instance of A to have different element values in the array a then you're making the mistake of trying to make the array const to begin with. You should just be doing this:

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

#include <iostream>

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;
}

回答by Daniel Bungert

Where I've a constant array, it's always been done as static. If you can accept that, this code should compile and run.

在我有一个常量数组的地方,它总是作为静态完成的。如果您可以接受,则此代码应该可以编译并运行。

#include <stdio.h>
#include <stdlib.h>

class a {
        static const int b[2];
public:
        a(void) {
                for(int i = 0; i < 2; i++) {
                        printf("b[%d] = [%d]\n", i, b[i]);
                }
        }
};

const int a::b[2] = { 4, 2 };

int main(int argc, char **argv)
{
        a foo;
        return 0;
}

回答by Trap

You can't do that from the initialization list,

你不能从初始化列表中做到这一点,

Have a look at this:

看看这个:

http://www.cprogramming.com/tutorial/initialization-lists-c++.html

http://www.cprogramming.com/tutorial/initialization-lists-c++.html

:)

:)

回答by CharlesB

A solution without using the heap with std::vectoris to use boost::array, though you can't initialize array members directly in the constructor.

不使用堆的解决方案std::vector是使用boost::array,尽管您不能直接在构造函数中初始化数组成员。

#include <boost/array.hpp>

const boost::array<int, 2> aa={ { 2, 3} };

class A {
    const boost::array<int, 2> b;
    A():b(aa){};
};

回答by Pete

How about emulating a const array via an accessor function? It's non-static (as you requested), and it doesn't require stl or any other library:

如何通过访问器函数模拟 const 数组?它是非静态的(根据您的要求),并且不需要 stl 或任何其他库:

class a {
    int privateB[2];
public:
    a(int b0,b1) { privateB[0]=b0; privateB[1]=b1; }
    int b(const int idx) { return privateB[idx]; }
}

Because a::privateB is private, it is effectively constant outside a::, and you can access it similar to an array, e.g.

因为 a::privateB 是私有的,所以它在 a:: 之外实际上是常量,并且您可以像访问数组一样访问它,例如

a aobj(2,3);    // initialize "constant array" b[]
n = aobj.b(1);  // read b[1] (write impossible from here)

If you are willing to use a pair of classes, you could additionally protect privateB from member functions. This could be done by inheriting a; but I think I prefer John Harrison's comp.lang.c++ post using a const class.

如果您愿意使用一对类,您还可以保护 privateB 免受成员函数的影响。这可以通过继承 a 来完成;但我想我更喜欢使用 const 类的 John Harrison 的 comp.lang.c++ 帖子。

回答by Nefzen

interestingly, in C# you have the keyword const that translates to C++'s static const, as opposed to readonly which can be only set at constructors and initializations, even by non-constants, ex:

有趣的是,在 C# 中,你有关键字 const 转换为 C++ 的静态常量,而不是只读,它只能在构造函数和初始化时设置,即使是非常量,例如:

readonly DateTime a = DateTime.Now;

I agree, if you have a const pre-defined array you might as well make it static. At that point you can use this interesting syntax:

我同意,如果您有一个 const 预定义数组,您最好将其设为静态。那时你可以使用这个有趣的语法:

//in header file
class a{
    static const int SIZE;
    static const char array[][10];
};
//in cpp file:
const int a::SIZE = 5;
const char array[SIZE][10] = {"hello", "cruel","world","goodbye", "!"};

however, I did not find a way around the constant '10'. The reason is clear though, it needs it to know how to perform accessing to the array. A possible alternative is to use #define, but I dislike that method and I #undef at the end of the header, with a comment to edit there at CPP as well in case if a change.

但是,我没有找到绕过常量“10”的方法。原因很清楚,它需要知道如何访问数组。一种可能的替代方法是使用#define,但我不喜欢该方法,并且我在标题末尾使用#undef,并在 CPP 中添加注释以进行编辑,以防发生更改。