我在初始化这个结构时遇到了麻烦(例如简化)
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
。
我该怎么办?
谢谢
答案 0 :(得分:3)
为什么不删除最后一个const
?
struct S{ const float * const * data;};
这样你可以随意初始化data
,但它仍然无法用于修改指向的任何内容。
data
本身可以修改,但如果要防止它,它应该只是private
。
答案 1 :(得分: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;
}
答案 2 :(得分:0)
@ CaptainObvious的答案是正确的。为S编写一个构造函数,获取它需要的任何参数,并使用成员初始化而不是赋值语句来设置'data'。
答案 3 :(得分: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
成员必须初始化为对象构造的一部分。您必须在初始化程序中以某种方式指定它们,或者必须在类中设置它们的值,以便它们在构造时设置。
在构造过程中传递它们的一种方法,但是以可读的方式使用第二个对象来帮助初始化:
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;
第二种方法依赖于编译器扩展;虽然不是标准的C ++,但gcc和clang在C ++中实现了C99指定的初始化器。 VC ++没有实现这一点。
S s { .a = x, .b = y, .c = z };