std :: cout&operator <<的奇怪行为

the*_*ine 1 c++ gnu

我今天遇到了一些奇怪的东西,我想知道你们这里有没有人能解释发生了什么......

这是一个示例:

#include <iostream>
#include <cassert>
using namespace std;

#define REQUIRE_STRING(s)           assert(s != 0)
#define REQUIRE_STRING_LEN(s, n)    assert(s != 0 || n == 0)

class String {
public:
        String(const char *str, size_t len) : __data(__construct(str, len)), __len(len) {}
        ~String() { __destroy(__data); }

        const char *toString() const {
            return const_cast<const char *>(__data);
        }

        String &toUpper() {
            REQUIRE_STRING_LEN(__data, __len);
            char *it = __data;
            while(it < __data + __len) {
                if(*it >= 'a' && *it <= 'z')
                    *it -= 32;
                ++it;
            }
            return *this;
        }

        String &toLower() {
            REQUIRE_STRING_LEN(__data, __len);
            char *it = __data;
            while(it < __data + __len) {
                if(*it >= 'A' && *it <= 'Z')
                    *it += 32;
                ++it;
            }
            return *this;
        }

private:
        char *__data;
        size_t __len;

protected:
        static char *__construct(const char *str, size_t len) {
            REQUIRE_STRING_LEN(str, len);
            char *data = new char[len];
            std::copy(str, str + len, data);
            return data;
        }

        static void __destroy(char *data) {
            REQUIRE_STRING(data);
            delete[] data;
        }
};

int main() {
    String s("Hello world!", __builtin_strlen("Hello world!"));

    cout << s.toLower().toString() << endl;
    cout << s.toUpper().toString() << endl;

    cout << s.toLower().toString() << endl << s.toUpper().toString() << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在,我原以为输出是:

hello world!
HELLO WORLD!
hello world!
HELLO WORLD!
Run Code Online (Sandbox Code Playgroud)

但相反,我得到了这个:

hello world!
HELLO WORLD!
hello world!
hello world!
Run Code Online (Sandbox Code Playgroud)

我真的不明白为什么第二个toUpper没有任何影响.

Ser*_*gGr 20

这完全是因为你的代码

cout << s.toLower().toString() << endl << s.toUpper().toString() << endl;
Run Code Online (Sandbox Code Playgroud)

以及如何toLowertoUpper实现.以下代码应按预期工作

cout << s.toLower().toString() << endl;
cout << s.toUpper().toString() << endl;
Run Code Online (Sandbox Code Playgroud)

问题是,toLowertoUpper没有创建新的对象,但修改现有的对象.当你在同一个块中调用几个修改方法并将此对象作为参数传递给某个地方时,行为是未定义的.

编辑:这类似于流行的问题,将会是什么结果

int i = 5;
i += ++i + i++;
Run Code Online (Sandbox Code Playgroud)

这里的正确答案是相同的:undefined.您可以谷歌搜索C++中的"序列点"以获得更深入的解释.

  • 我认为这个术语有点像"没有插入序列点的值的连续变化". (2认同)