初始化模板C++类中const的const数组



我想创建一个template <typename T> class InitConst,其中一些成员是T的数组。我想在类对象初始化期间填充这些数组,然后确保这些数组不会再更改,所以我为每个这样的数组定义了一个成员const T* const v(我知道第一个常量指元素,第二个常量指指针(。

对此进行的实验使我得出结论,将"v"定义为"const指针到const"迫使我在最终用该数组的地址初始化"v"之前分配并填充相应的数组。此外,由于我无法在类"InitConst"的构造函数内部初始化"v",我得出结论,我需要一个辅助函数,其作用是(a(获取构造函数参数,(b(分配和填充数组,以及(c(使用一些静态指针来保存这些数组的地址。这些静态指针最终将被构造函数用来初始化常量指针,所以我得到了这样的代码:

template <typename T>
class InitConst
  {
  public:
  const T* const v1;
  const T* const v2;
  const T* const v3;
  InitConst(T a1, T a2, T a3, int n)
    : v1( init(a1,a2,a3,n) ), v2(init_p.temp_v2), v3(init_p.temp_v3)
    { }
  private:
  struct Tinit {
    T* temp_v1;
    T* temp_v2;
    T* temp_v3;
    };
  static Tinit init_p;
  T* init (T a1, T a2, T a3, int n)
    {
    init_p.temp_v1 = new T[n];
    init_p.temp_v2 = new T[n];
    init_p.temp_v3 = new T[n];
    // populate "temp_v1", "temp_v2" and "temp_v3" using the method's arguments.
    return init_p.temp_v1;
    } // End method init.
  }; // End class InitConst.
template <typename T>
typename InitConst<T>::Tinit InitConst<T>::init_p;

这段代码按预期编译和工作,但我认为这种设计是扭曲的:我习惯于简单的代码,首先分配一个数组,然后计算它的元素(这两件事通常发生在构造函数的主体中(,然后使用数组。相比之下,构造函数本身几乎什么都不做:它的角色被转移到方法"init",该方法实际上创建了数组,并使用一些辅助指针将它们传递回构造函数。

然后我想知道:

a( 如果我决定将每个指针声明为"const-pointer-to-const",或者有更干净的方法,那么这种设计(或类似的设计(是必要的吗?

b( 将每个指针声明为"const-pointer-to-const"是防止类被滥用的一种方法,但也许我不需要那么多。一种稍微不那么严格的方法是将"v1"及其兄弟姐妹声明为私人成员,这样它们就不能从类外更改。然而,这样做也会防止从类外读取它们,并且我不希望每个数组"vx"都有一个"read_vx"方法。那么我该怎么办呢?也就是说,什么方法可以获得更可读的代码,并且至少可以保证数组不能从类外更改?

提前谢谢,很抱歉写了这么长的文章。

编辑:正如我在下面评论的那样,在我的真实代码中,我想要计算的各种数组可以更有效地计算在一起,这就是为什么我使用单个"init"函数。我在示例中提供的"init"("a1"、"a2"、"a3"(的参数实际上是误导性的。

根据问题的更新,您仍然可以干净地处理初始化,并比我之前提出的进一步减少代码。由于知道数据是可写的,因此可以使用const_cast并在构造函数中进行初始化。

template <typename T>
class InitConst
{
public:
    const T* const v1;
    const T* const v2;
    const T* const v3;
    InitConst(T a1, T a2, T a3, int n)
        : v1( new T[n] ), v2( new T[n] ), v3( new T[n] )
    {
        T* t1 = const_cast<T*>(v1);
        T* t2 = const_cast<T*>(v2);
        T* t3 = const_cast<T*>(v3);
        //  do intialization here
    }
};



[注意:根据OP的意见,以下解决方案不可用]

最好让init一次帮助初始化单个成员变量,而不是全部三个。这将显著减少代码并消除对static变量的需要,该变量将需要为与InitConst一起使用的每个类型的T定义。您还可以将init更改为静态,以防止意外使用尚未初始化的成员变量。

template <typename T>
class InitConst
{
public:
    const T* const v1;
    const T* const v2;
    const T* const v3;
    InitConst(T a1, T a2, T a3, int n)
        : v1( init(a1,n) ), v2( init(a2,n)), v3(init(a3,n))
    { }
private:
    static const T* init (T a, int n)
    {
        T* v = new T[n];
        // populate "v" from "a"
        return v
    }
};

不需要struct Tinit:

tempalate<typename T>
InitConst::InitConst(T a1, T a2, T a3, int n)
  : v1(init(a1,n)), v2(init(a2,n)), v3(init(a3,n))
{}
tempalate<typename T>
T* InitConst::init (T a, int n)
{
  T* result = new T[n];
  // TODO: populate result using a
  return result
};
// TODO implement destructor, copy constuctor and
// copy assignement operator

最新更新