首页 新闻 会员 周边

c++11使用{0}初始化结构体的问题

0
悬赏园豆:50 [已解决问题] 解决于 2021-12-27 15:55

std::string, std::function类型是否可以用{0}初始化?
示范代码如下:

struct c_user
{
    int id;
    char name[64];
};

struct cpp_user
{
    int id;
    std::string name;
};

int main() {
    c_user user1 = {0}; /// c语言常用
    cpp_user user2{0}; /// c++11下是否安全?

    std::string name{0}; /// gcc没报错,但是否正确?
    //std::string name2(0); /// 会崩溃
    return 0;
}
c++
问题补充:

最终决定弃用这种用法
之前描述不清楚,补充说明一下:
1 "是否安全",我希望是c++规范明确指出这是一个特性,而不是一个bug。按我的理解, std::string name{0}, std::string name(0)应该是相同的语义,如果会崩溃,两者都应该崩溃。测试其他的string类的实现,如Glib::ustring,Glib::ustring name{0}也是会崩溃的。这说明支持{0}初始化并不是所有string类的通用特性。
2 如果这是一个特性,我也希望个人写的类也有这个特性,如

//期望(0) {0}能调用到不同的构造函数,但不清楚如何实现
class mystring {
public:
    //期望{0}能调用此构造函数,但事实上不会
    mystring(){
        std::cout << "default " << std::endl;
    }

    // mystring{0}  mystring(0)都会调用此构造
    mystring(const char *s){
        std::cout << "const char " << (void *)s <<std::endl;
    }
};

3 如果不能确定,可能用下面的的方式初始化,起码心里有底些

struct cpp_user {
    int id{0};
    std::string name;
};
岚2022的主页 岚2022 | 初学一级 | 园豆:157
提问于:2021-12-17 16:36
< >
分享
最佳答案
0

如果自己看看是不是安全的,请看汇编,C语言的本质是帮你写汇编的工具,下面我们来解决下面的问题:

 cpp_user user2{0}; /// c++11下是否安全?

是安全的,我们来看一下它的反汇编:

001C894A  xor         eax,eax  
001C894C  mov         dword ptr [user2],eax  //ebp-80h
001C894F  lea         ecx,[ebp-7Ch]  
001C8952  call        std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (01C133Eh)  
001C8957  mov         dword ptr [ebp-4],0 

可以看出,你初始化cpp_user,会主动调用std::string的构造函数。

std::string name{0}; /// gcc没报错,但是否正确?

没报错的写法都是对的。

std::string name2(0); // 会崩溃

因为它会把0当作地址,调用构造函数进行处理,结果一般的0地址是不可读的。

所有的类型都可以用0初始化,因为在内存都是数据,至于怎么用就是你的问题了。

收获园豆:40
寂静的羽夏 | 小虾三级 |园豆:1781 | 2021-12-17 17:18

@岚2022 这么跟你说吧,name(0)name{0}不是一个东西,前者是用0这个地址作为字符串地址为参数调用构造函数,另一个是用0填充为一个字符串,并调用另一个构造函数进行初始化(以字符串作为参数),这个东西完完全全可以通过汇编进行判断。

寂静的羽夏 | 园豆:1781 (小虾三级) | 2021-12-19 15:30

@寂静的羽夏:"用0填充为一个字符串,并调用另一个构造函数进行初始化"这句话难以理解,可以修改下面代码,使(0) {0}能调用到不同的构造函数吗?

//期望(0) {0}能调用到不同的构造函数,但不清楚如何实现
class mystring {
public:
    //期望{0}能调用此构造函数,但事实上不会
    mystring(){
        std::cout << "default " << std::endl;
    }

    // mystring{0}  mystring(0)都会调用此构造
    mystring(const char *s){
        std::cout << "const char " << (void *)s <<std::endl;
    }
};
岚2022 | 园豆:157 (初学一级) | 2021-12-19 18:52

@岚2022: 当遇到C语言相关未知的东西的时候,汇编是最好的结论。我上面的所有结论基于汇编。这些事情是编译器为你做的,汇编是直接体现这个东西的。类的{}初始化应该是C++设计编译器的特性,C我记着不能用。汇编是最清楚但最难懂的语言,自己有能力研究研究。我之所以说是不同的构造函数,是因为构造string的函数地址是不一样的。怎么修改实现我不清楚。

寂静的羽夏 | 园豆:1781 (小虾三级) | 2021-12-19 20:31

@寂静的羽夏: 你这么说也没错,但代价太大,gcc stl库是开源的,也可以直接看stl源码。但这不符合我的需求,我希望代码让人一眼就能看懂,如果大部分人都不明白string{0}的语义,需要翻stl源码去研究,那这个语法就没有使用的必要,换一种大家都能看懂的语法就可以了,比如

struct cpp_user {
    int id{0};
    std::string name;
};
岚2022 | 园豆:157 (初学一级) | 2021-12-20 10:24
其他回答(2)
0

可以使用cpp_user user2{0};初始化,没有问题的。它会调用这个类的构造函数。
如果尝试下面的代码会输出init。

struct cpp_user
{
    int id;
    std::string name;
    cpp_user(int a){
      cout<<"init";
    }
};

string同理。
2.

string name2(0);

不可以写,因为string的构造函数的写法是:

string name2("init");

参数可以是一个C风格字符串(也就是char数组 or 指针),也可以是string类。
此时,系统会把0当作地址,也就是NULL地址,当作字符串来读取,NULL是不能读写的,导致运行错误。

收获园豆:10
计算机知识杂谈 | 园豆:470 (菜鸟二级) | 2021-12-18 18:52
0

std::string 初始化请用 std::string name{}

Smalldy | 园豆:430 (菜鸟二级) | 2022-06-17 14:06
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册