首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么我不能初始化一个具有统一初始化的字符串?

为什么我不能初始化一个具有统一初始化的字符串?
EN

Stack Overflow用户
提问于 2019-04-27 20:41:32
回答 1查看 448关注 0票数 2

我有一个模拟窗口的程序;因此,我将窗口的内容存储在一个成员数据content中,这是一个std::string类型:

代码语言:javascript
复制
class Window {
    using type_ui = unsigned int;
    public:
        Window() = default;
        Window(type_ui, type_ui, char);
        void print()const;

    private:
        type_ui width_{};
        type_ui height_{};
        char fill_{};
        std::string content_{};
        mutable type_ui time_{};
};

Window::Window(type_ui width, type_ui height, char fill) :
    width_{ width }, height_{ height }, fill_{ fill },
    content_{ width * height, fill } { // compile-time error here?
    //content( width * height, fill ) // works ok
}

void Window::print()const {
    while (1) {
        time_++;
        for (type_ui i{}; i != width_; ++i) {
            for (type_ui j{}; j != height_; ++j)
                std::cout << fill_;
            std::cout << std::endl;
        }
        _sleep(1000);
        std::system("cls");
        if (time_ > 10)
            return;
    }
}


int main(int argc, char* argv[]) {

    Window main{ 15, 25, '*' };
    main.print();

    std::string str{5u, '*'}; // compiles but not OK
    std::string str2(5u, '*'); // compiles and OK
    cout << str << endl; // ♣* (not intended)
    cout << str2 << endl; // ***** (ok)

    std::cout << std::endl;
}

正如您在上面看到的,我无法用content初始化成员curly-braces-initializer-list,编译器抱怨它是“缩窄类型”。但它适用于“直接初始化”。

  • 为什么我不能在上面的构造器初始化程序列表中使用卷大括号初始化列表来调用std::string(size_t count, char)
  • 为什么这个std::string str{5u, '*'}; // compiles but not OK可以工作,但却没有给出预期的ouptu?
  • 最重要的是,为什么同样的初始化在构造函数成员初始化列表上不起作用,而在main中工作(没有预期的结果)?
EN

回答 1

Stack Overflow用户

发布于 2019-04-27 20:45:12

  • 首先,因为std::string的构造函数sts::string(size_t count, char)是显式的,所以不能隐式调用它。
  • 第二,您不是在content{width * height, fill}中调用std::string(std::initializer_list<char>),而是实际上是在调用std::string(std::initializer_list<char>)。因此,表达式width * height生成一个无符号int,然后隐式转换为char,这是“相关类型”,因此对于实例,您传递了Window main{ 15, 25, '*' };,它生成(char)15 * 25 = (char)375,这是未定义的行为,因为该值溢出了signed char。您可以将计算机上的"♣“或其他值作为初始化程序列表中的第一个元素,但它是未定义的行为,"”作为初始化程序列表中的第二个元素。因此,您将传递std::initializer_list{'♣',''}。
代码语言:javascript
复制
- Use direct initialization as long as you are invoking an explicit constructor that has more than one parameter.

  • 第二个问题的答案是:“最重要的是,为什么同样的初始化在构造函数-成员初始化-列表上无效,而在main中工作(没有预期的结果)?”:

实际上,它与“构造器-成员-初始化-列表”没有任何关系,但实际上需要考虑以下几点:

代码语言:javascript
复制
    char c{ 127 }; // the maximum integer positive value that a signed char can hold so no narrowing conversion here. So it is OK.

    char c2{ 128 }; // Now 128 overflows the variavle c2. c2 is of type char and as you know it can hold positive values in range 0 to 127 and negative -1 to -128
    unsigned char uc{ 255 }; // ok because an unsigned char can hold 255
    unsigned char uc2{ 300 }; // error as the error above. An unsigned char can hold 255 as max positive value.

    unsigned char uc3 = 321; // ok // ok but you may get a warning. a Copy-initialization is not safe.
    cout << uc3 << endl; // you may get `A`. 321 % 256 = 65. 65 % 256 = 65. 65 in ASCII in some implementations it represents the character "A".

虽然上面溢出uc3不是件好事,但结果是明确的.(溢出未签名的Xtype)。

  • 但是看看这个: char c3 = 321;// signed char溢出cout << c3 << endl;//您可能会得到"A“并认为它是正确的。

上面是未定义的行为。不要试图溢出签名类型。

代码语言:javascript
复制
constexpr int i = 10;
constexpr int j = 5;
std::string str{ i * j, 'f' }; // ok as long as the values are constexpr and don't cause any narrowing conversion this value: 10 * 5 = 50 which is a well defined signed-char value.

int i = 10;
int j = 5;
std::string str{ i * j, 'f' }; // error. the values of i and j are not constant thus it may overflow a signed char causing narrowing conversion thus the compiler is wise enough to prevent this initialization.
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55884699

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档