Const *成员变量初始化c++

const * const * member variable initialization c++

本文关键字:初始化 c++ 变量 成员 Const      更新时间:2023-10-16

我在初始化这个结构体时遇到了麻烦(例如简化)

struct S{ const float * const * const data;};

基本上,我有一个浮点缓冲区的缓冲区,我使用const来确保使用S的人不能改变这个成员的任何内容(只读)。

我的问题是,这是复杂的,难以阅读初始化,我想使用一个lambda返回一个const S,所以我可以初始化成员在我的lambda写成员名:s.data = ptr;

现在这段代码很复杂,我想知道有什么更好的解决方案。

当然,有struct S{float ** data;}const S不能有效地保护成员的内容,我不能修改S::data,但我可以修改*S::data

我该怎么办?

Thank you

为什么不直接删除最后一个const呢?

struct S{ const float * const * data;};

这样,你可以初始化data,但它仍然不能用来修改任何指向的东西。

data本身是可以修改的,但是如果不允许的话,它应该是private

推荐的方法是给S添加一个构造函数。这允许你在函数初始化列表中设置data的值。

struct S
{
    explicit S(const float *const *const d) : data(d) {}
    const float * const * const data;
};
S GetS()
{
    float **data = GetData();
    return S(data);
}

如果你想限制谁可以在S::data初始化后修改它,你可以成员变量并使用friendship来允许访问。这需要将data成员封装在提供转换和赋值操作符的附加结构体中。

struct Outer
{
    struct S
    {
    private:
        struct ConstBox
        {
            friend Outer;
            ConstBox(const ConstBox& other) : data_(other.data_) {}
            explicit ConstBox(const float *const *const data) : data_(data) {}
            operator const float* const* () const { return data_; }
        private:
            ConstBox& operator=(const float * const * data)
            {
                data_ = data;
                return *this;
            }
            const float * const * data_;
        };

    public:
        S() : data(nullptr) {}
        explicit S(const float *const *const d) : data(d) {}
        ConstBox data;
    };
    S DoSomething() const
    {
        S   s(nullptr);
        auto f = []() -> S
        {
            S s;
            s.data = new float*[10];
            return s;
        };
        return f();
    }
};

typedef Outer::S S;
void FailTest()
{
    S   s;
    s.data = nullptr; // <-- fails
    float** v1 = s.data; // <-- fails
    const float** v1 = s.data; // <-- fails
    // These are ok
    const float* const* v2 = s.data;
}

@CaptainObvious的答案是正确的。为S编写一个构造函数,接受它需要的任何参数,并使用成员初始化器而不是赋值语句来设置'data'。

对于您的简化示例,我将简单地做:

struct S{ float const * const * const data;};
auto create_buffer() -> float const * const * {
    float **buf;
    /* ... compute buffer contents */
    return buf;
}
S s {create_buffer()};

但是,您在评论中提到您有许多成员,并且根据顺序初始化成员不够清楚。

struct S { const A a; const B b; const C c; };
S s {x,y,z}; // order based, not readable enough.

const成员必须作为对象构造的一部分初始化。必须在初始化器中以某种方式指定它们,或者必须在类中设置它们的值,以便在构造时设置它们。


解决方案1

在构造过程中传递它们的一种方法是使用第二个对象来帮助初始化,但以可读的方式:

struct S_initializer { A a; B b; C c; }
struct S {
  const A a; const B b; const C c;
  S(S_initializer &s) : a(s.a), b(s.b), c(s.c) {}
};
S make_S() {
  S_initializer s;
  s.a = x;
  s.b = y;
  s.c = z;
  return S{s};
}

上面涉及一些重复,您可以通过将初始化助手对象设置为S的const成员来避免重复:

struct S {
  const S_initializer m;
  S(S_initializer &s) : m{s} {}
};
S make_S() {
  S_initializer s;
  s.a = x;
  s.b = y;
  s.c = z;
  return S{s};
}

权衡的是,现在要访问S的成员,你必须在那里有一个额外的.m:

A a = s.m.a; // versus just s.a;

解决方案2

第二个方法依赖于编译器扩展;虽然不是标准的c++,但gcc和clang在c++中实现了C99指定初始化式。vc++没有实现这个

S s { .a = x, .b = y, .c = z };