通过传递引用或返回它来初始化结构是更好的风格吗?
Is it better style to initialize a structure by passing a reference or returning it?
假设我有以下内容:
typedef struct {
int x;
int y;
char a;
char b;
} myStruct;
通过将引用传递给空函数或从函数返回 myStruct
来创建一个带有函数的新 myStruct
更好吗?
void init(myStruct* s){
//some code
}
int main(){
myStruct s;
init(&s);
return 0;
}
对
myStruct init(){
myStruct r;
//some code
return r;
}
int main(){
myStruct s = init();
return 0;
}
这基本上只是惯例。第一种风格在 C 代码中更常见,第二种风格在 C++ 代码中更常见。
在 C++ 中,他们会说第二个是首选,因为在第一个中,如果你分配了一个结构但忘记调用 init
那么你可能会遇到 "headless object" 的混乱情况正在传递。
在 C++ 中,init
函数通常只是一个构造函数,因此不存在初始化失败的可能性。
在 C++ 中,如果您打开优化,效率不会有任何差异,编译器将执行 "copy elision" 并优化第二个,使其看起来与第一个相似。
就个人而言,我经常对简单数据对象使用聚合初始化:
struct MyStruct {
int x;
int y;
char a;
char b;
};
int main()
{
MyStruct s = {10, 20, 'e', 'u'};
}
或硬编码默认值如下:
struct MyStruct {
int x;
int y;
char a;
char b;
};
const MyStruct MyDefault_A = {0, 0, 'a', 'z'};
const MyStruct MyDefault_B = {10, 20, 'e', 'u'};
int main()
{
MyStruct s = MyDefault_A;
}
这取决于您将什么视为初始状态。对于某些人来说它意味着全零,对于其他人来说它意味着默认状态或有意义的状态。
不同的初始状态定义你有不同的方式来做到这一点。
对于归零结构,你只需要
struct mystruc s = {0};
如果一个结构需要特定的值初始化,它可能看起来像:
struct mystruc s = {1, 2, NULL, 0x1234};
对于non-trival初始化,我个人喜欢这样:
struct mystruc s;
if ( mystruc_init(&s) < 0 ) it_is_fail();
IMO,你的第二种方法 myStruct s = init();
并不比上述方法更多地强制初始化,程序员可能仍然会 myStruct s;
而没有得到警告,我个人讨厌返回复杂数据类型的局部变量.
如果你的结构初始化不会失败,我个人更喜欢并建议你只按值return它,因为这就是你最终想要的概念上:让函数在其范围之外传递一些值——这正是 return 值的设计目的。
如果你的手指习惯了"this datatype needs initialization"这种成语,那么你就不太可能忘记
MyStruct foo = init_myStruct();
比执行两步 "declare and fill" 过程。更容易阅读,更容易编写。
还必须注意,传递指针的方法不能用于初始化 const
限定的结构, 所以你有基本上别无选择,只能 return 按值计算。
假设我有以下内容:
typedef struct {
int x;
int y;
char a;
char b;
} myStruct;
通过将引用传递给空函数或从函数返回 myStruct
来创建一个带有函数的新 myStruct
更好吗?
void init(myStruct* s){
//some code
}
int main(){
myStruct s;
init(&s);
return 0;
}
对
myStruct init(){
myStruct r;
//some code
return r;
}
int main(){
myStruct s = init();
return 0;
}
这基本上只是惯例。第一种风格在 C 代码中更常见,第二种风格在 C++ 代码中更常见。
在 C++ 中,他们会说第二个是首选,因为在第一个中,如果你分配了一个结构但忘记调用 init
那么你可能会遇到 "headless object" 的混乱情况正在传递。
在 C++ 中,init
函数通常只是一个构造函数,因此不存在初始化失败的可能性。
在 C++ 中,如果您打开优化,效率不会有任何差异,编译器将执行 "copy elision" 并优化第二个,使其看起来与第一个相似。
就个人而言,我经常对简单数据对象使用聚合初始化:
struct MyStruct {
int x;
int y;
char a;
char b;
};
int main()
{
MyStruct s = {10, 20, 'e', 'u'};
}
或硬编码默认值如下:
struct MyStruct {
int x;
int y;
char a;
char b;
};
const MyStruct MyDefault_A = {0, 0, 'a', 'z'};
const MyStruct MyDefault_B = {10, 20, 'e', 'u'};
int main()
{
MyStruct s = MyDefault_A;
}
这取决于您将什么视为初始状态。对于某些人来说它意味着全零,对于其他人来说它意味着默认状态或有意义的状态。
不同的初始状态定义你有不同的方式来做到这一点。
对于归零结构,你只需要
struct mystruc s = {0};
如果一个结构需要特定的值初始化,它可能看起来像:
struct mystruc s = {1, 2, NULL, 0x1234};
对于non-trival初始化,我个人喜欢这样:
struct mystruc s;
if ( mystruc_init(&s) < 0 ) it_is_fail();
IMO,你的第二种方法 myStruct s = init();
并不比上述方法更多地强制初始化,程序员可能仍然会 myStruct s;
而没有得到警告,我个人讨厌返回复杂数据类型的局部变量.
如果你的结构初始化不会失败,我个人更喜欢并建议你只按值return它,因为这就是你最终想要的概念上:让函数在其范围之外传递一些值——这正是 return 值的设计目的。
如果你的手指习惯了"this datatype needs initialization"这种成语,那么你就不太可能忘记
MyStruct foo = init_myStruct();
比执行两步 "declare and fill" 过程。更容易阅读,更容易编写。
还必须注意,传递指针的方法不能用于初始化 const
限定的结构, 所以你有基本上别无选择,只能 return 按值计算。