1

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

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

基本上我有一个浮动缓冲区的缓冲区,并且我使用 const 来确保使用 S 的人不能对此成员进行任何更改(只读)。

我的问题是这很复杂且难以初始化,我想使用一个返回 const S 的 lambda,因此我可以通过编写成员名称来初始化我的 lambda 中的成员:s.data = ptr;

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

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

我应该怎么做 ?

谢谢

4

4 回答 4

3

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

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

这样你就可以随心所欲地初始化data,它仍然不能用来修改它指向的任何东西。

data本身可以被修改,但如果被阻止,它应该只是private.

于 2013-05-21T22:56:34.500 回答
1

推荐的方法是添加一个构造函数到S. 这允许您在 ctor 初始化程序列表中设置数据的值。

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在初始化后限制谁可以更改,您可以将成员变量装箱并使用友谊来允许访问。这需要将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;
}
于 2013-05-21T22:51:35.520 回答
0

@CaptainObvious 的答案是正确的。为 S 编写一个构造函数,获取它需要的任何参数,并使用成员初始化程序而不是赋值语句来设置“数据”。

于 2013-05-21T23:02:13.960 回答
0

使用您的简化示例,我只需执行以下操作:

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 };
于 2013-05-22T00:02:39.093 回答