链接的 ostream 内部行为及其在 MSVC 上的结果(与 Clang 相比)

2024-04-28

MSVC 与 GCC / Clang 的流、内部字符串和操作排序问题

大家好,

我最近刚刚开始更认真地使用 MSVC 来完成我的一个跨平台项目,同时通过以下方式测试输出chainedSTD 流(IE。一系列的obj.foo() << endl << obj.bar() << endl << [..etc])我在使用内部更新的字符串时遇到了一种行为,既没有预料到,也没有在 Linux 上遇到过GCC or Clang.

编译器版本为 GCC 7.5、Clang 11.0 和 MSVC 14.0,均启用了 c++17 标准(尽管尚未完成)。 [edit:使用 MSVC 16.6.3 时出现同样的问题(编译器内部版本 19.26.28806.0) ]

为了快速理解这里的问题的简化版本:

#include <iostream>
#include <ostream>
#include <string>

class Sample {
    std::string s;
    int x;

public:
    Sample() = default;

    friend std::ostream& operator<<(std::ostream& os, const Sample& a);

    // Update internal value, return the object.
    Sample const& set(std::string ss, int xx) { 
        s = ss; 
        x = xx;  
        return *this; 
    }
    
    // Update internal value, return the string.
    std::string const& setStr(std::string ss, int xx) { 
        set(ss, xx);  
        return s; 
    }
    
    // Update internal value, return the int.
    int const& setX(std::string ss, int xx) { 
        set(ss, xx);  
        return x; 
    }
};

// Output the object integer, same behavior with the string
// or if we flush inside or anything.
std::ostream& operator<<(std::ostream& os, Sample const& a)
{
  os << a.x;
  return os;
}

int main() {
    Sample a;
                                                 // GCC / Clang  |    MSVC   
    std::cerr << a.set("0", 0) << std::endl      // 0                 0
              << a.set("1", 1) << std::endl      // 1                 0
              << a.set("2", 2) << std::endl;     // 2                 0

    std::cerr << "content : " << a << std::endl; // 2                 0
    
    a.set("",-1); std::cerr << std::endl;

    std::cerr << a.setStr("0", 0) << std::endl   // 0                 0
              << a.setStr("1", 1) << std::endl   // 1                 0
              << a.setStr("2", 2) << std::endl;  // 2                 0

    std::cerr << "content : " << a << std::endl; // 2                 0
    
    a.set("",-1); std::cerr << std::endl;

    std::cerr << a.setX("0", 0) << std::endl     // 0                 0
              << a.setX("1", 1) << std::endl     // 1                 1
              << a.setX("2", 2) << std::endl;    // 2                 2

    std::cerr << "content : " << a << std::endl; // 2                 2
}

看来,对于字符串或流式版本,所有操作都使用相同的最终变异字符串对象,但我不明白为什么会这样(再次,在 GNU / Linux 工具链上没有问题).

我可能会补充一点,如果我们解开流,这个排序问题就会消失:

    std::cerr << a.set("0", 0) << std::endl; // "0"
    std::cerr << a.set("1", 1) << std::endl; // "1"
    std::cerr << a.set("2", 2) << std::endl; // "2"

我一开始以为是冲洗问题,但测试显示并非如此。实际使用endl甚至flush在每个链式调用之间不执行任何操作。

它可能是 Visual-C++ 甚至CPP101已知的基本行为(关于记忆之类的),但我对此一无所知,所以我将非常感谢您提供的任何建议,因为它在我的书中非常奇怪。

Thanks !

Edit

具有讽刺意味的是,我已经能够在 GNU / Linux 上重现该问题(使用我的项目,而不是上面的代码),试图通过模板变量扩展找到替代方案,但这里的事情是:

void println() // base function
{
  std::cerr << std::endl;
}

template<typename T, typename... Ts>
constexpr void println(T head, Ts... tail)
{
  std::cerr << head << std::endl;
  println(tail...);
}

int main()
{
  int i;

  i = 0;
  println(++i, ++i, ++i); // 3 3 3
  i = 0;
  println(i++, i++, i++); // 2 1 0
}

在 MSVC 上,流似乎像这种后增量可变参数模板一样工作:结果在某种程度上是向后的(或者更像是后递归应用)。我不确定这对我来说是否有意义。


根据Microsoft C++ 语言一致性表 https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=vs-2019, C++17 的更改了评估顺序规则 https://en.cppreference.com/w/cpp/language/eval_order直到 VS 2017 15.7 才实现。 14.0 还不够好。你将不得不升级或不连锁。

Testing

#include <iostream>


int f()
{
    static int i = 0;
    return i++;
}

int main()
{
    std::cout << f() << f();
}

C++17 之后应该产生 01

如果不打开 C++17 支持(属性 -> 配置属性 -> 语言 -> C++ 语言标准 = 默认),我会得到 10,函数将被反向求值。

通过“属性”->“配置属性”->“语言”->“C++ 语言标准 = ISO C++17 标准 (/std:c++17)”,我得到了预期的 01。

但如果我运行提问者的代码......我仍然看到不正确的响应。删除大部分示例并添加额外的调试行(并替换cerr with cout看看那里是否有一些深层的魔力)我明白了

#include <iostream>
#include <ostream>
#include <string>

class Sample {
    std::string s;
    int x = 0;

public:
    Sample() = default;

    friend std::ostream& operator<<(std::ostream& os, const Sample& a);

    // Update internal value, return the object.
    Sample const& set(std::string ss, int xx) {
        std::cout << "in func with " << ss << std::endl;
        s = ss;
        x = xx;
        return *this;
    }
};

// Output the object integer, same behavior with the string
// or if we flush inside or anything.
std::ostream& operator<<(std::ostream& os, Sample const& a)
{
    os << a.x;
    return os;
}

int main() {
    Sample a;
    // GCC / Clang  |    MSVC   
    std::cout << a.set("0", 0) << std::endl      // 0                 0
        << a.set("1", 1) << std::endl      // 1                 0
        << a.set("2", 2) << std::endl;     // 2                 0

    std::cout << "content : " << a << std::endl; // 2                 0
}

和输出



in func with 2
in func with 1
in func with 0
0
0
0
content : 0
  

显然是被称为倒退。我必须放弃这个并完成一些有偿工作,但要么我误读了

  1. 在移位运算符表达式中E1<<E2 and E1>>E2,每个值的计算和副作用E1在每次值计算和副作用之前排序E2

(引用 cppreference https://en.cppreference.com/w/cpp/language/eval_order)或者有什么可疑的事情发生。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

链接的 ostream 内部行为及其在 MSVC 上的结果(与 Clang 相比) 的相关文章

随机推荐

  • EF Core 5.0 中的多对多关系是否可以配置为仅保留一个导航属性(在一侧)?

    我已使用以下代码配置了 DbContext EF Core 5 0 protected override void OnModelCreating ModelBuilder modelBuilder modelBuilder Entity
  • 如何使用 Chart.js 在堆积条形图中显示内联值?

    我正在使用 Chart js 库在堆叠条形图中显示一些值 但我正在努力找出如何显示条形图中的值 即 现在 我有以下代码 可以在条形顶部显示数字 但我想知道如何在条形内部显示它们 var numberWithCommas function x
  • 如何使用 UIImagePickerController CropRect

    我刚刚找到了一种方法来更改裁剪框的矩形 该裁剪框在捕获图像后出现UIImagePickerViewController 这可以在以下帮助下完成UIImagePickerControllerCropRect 但我不知道如何使用它 最初的裁剪框
  • 在 Python 的内置数字类型上,repr 和 str 总是相同吗?

    Are repr and strPython 内置数字类型相同 int bool float and complex 或者是否存在 深奥的 两者可能产生不同结果的情况 SO的相关问题 例如this one https stackoverfl
  • 在 iOS6 中处理手势识别器

    显然 当你有手势识别器和手势识别器时 iOS 6 会尝试自动处理这种情况 UIButton在同一个地方 用同一个手势被激活 当您想要单击按钮而不是激活手势识别器时 这种新的自动处理可以解决问题 但是产生了一个新问题当您希望手势识别器起作用时
  • 将多列传递给 groupby.transform

    据我所知 当您使用 DataFrame 列调用 groupby transform 时 该列将传递给转换数据的函数 但我无法理解的是如何将多个列传递给函数 people DataFrame np random randn 5 5 colum
  • OpenGL 的每个组件 alpha 通道?

    是否可以使用 OpenGL 对每个组件使用一个 alpha 通道 一个用于红色 一个用于绿色 一个用于蓝色 进行混合 如果没有 有哪些可能的解决方法 这不是直接支持的东西 不过 您自己实现起来相当容易 使用 3 通道 alpha 纹理渲染三
  • Espresso,查找对话框并将其关闭

    我试图找到一个对话框取消按钮并将其推入 Espresso UI 测试 但我做不到 这是我的代码 onView withId R id dialog close button check matches isDisplayed 最好的解决方案
  • 使用两个键执行自动完成 - Material UI with React

    当使用两个值之一搜索时 我试图自动完成输入 title and year 但是 它仅在我搜索时才有效title 当我搜索时year 它不显示任何选项 示例代码 export default function ComboBox return
  • 检查字符串是否多次包含子字符串[重复]

    这个问题在这里已经有答案了 要搜索字符串内的子字符串 我可以使用contains 功能 但是如何检查一个字符串是否多次包含子字符串呢 优化这一点 对我来说 知道有多个结果而不是有多少就足够了 尝试利用快速IndexOf and LastIn
  • 如何将函数转发/别名/委托给方法?

    我想将函数转发到另一个模块中的方法 而不重复所有类型注释 也不手动传递参数 我该怎么做 mod other mod static client other mod Client other mod Client new async fn s
  • 如何获得 GTK 中的默认颜色?

    Context 在 GTK 3 中 人们可以设置自己的主题 甚至默认主题 Adwaita 也提供两种变体 浅色和深色 当我编写自己的小部件 用Python 时 我需要获取这些颜色以避免在黑色上绘制黑色或在白色上绘制白色 Question 如
  • 如何编辑 .csproj 文件

    当我使用 NET Framework 4 0 MSBUILD EXE 文件编译 csproj 文件时 出现错误 在 website01 csproj 的当前上下文中找不到 lable01 实际上 我需要添加每个 ASP NET 页面及其代码
  • 如何在 Mongoose 中设置文档创建的 TTL 日期?

    我正在尝试做一个promoCodeMongoose 中的架构 创建时 我需要能够设置促销代码的到期日期 促销代码不一定相同TTL 我在看这个问题 https stackoverflow com questions 14597241 sett
  • 如何将自定义http标头添加到角度模块联合remoteEntry.js加载调用?

    我有一个主机应用程序和一些微前端应用程序都是 Angular 15 我用过 angular architects module federation 15 0 3 一切工作正常 除了我无法拦截加载 mfe 应用程序的 remoteEntry
  • 如何用opengl制作2D地形?

    我想制作一个简单的二维地形 只有一些颠簸和高度变化 我想过只使用随机数来描述某个顶点的高度 但我不知道如何从中制作一个网格 我正在寻找一种方法来查找地形的顶点和索引缓冲区 我该怎么做呢 您可以仅将 GL POLYGON 与所有顶点的列表一起
  • Delphi是否存在无锁队列“多个生产者-单个消费者”?

    我发现了几个针对单个生产者 单个消费者的实现 但没有找到多个生产者 单个消费者的实现 Delphi是否存在 多个生产者 单个消费者 的无锁队列 无锁队列全线程库 http otl 17slon com支持多个生产者 您可以将它与线程库分开使
  • #region 描述编译到.net 中的.exe 中?

    region endregion 指令 描述 是否编译到 NET 中的 EXE 中 我知道注释不是 但我经常在一个区域内对代码组进行分块并给出有用的描述 我想确保这些描述在我编译的代码中不可见 我不是在寻找混淆信息 不过 谢谢 不 他们不是
  • 包括 pandas groupby 聚合中缺失的值组合

    Problem 在 pandas groupby 聚合的输出中包括所有可能的值或值的组合 Example 示例 pandas DataFrame 有三列 User Code and Subtotal import pandas as pd
  • 链接的 ostream 内部行为及其在 MSVC 上的结果(与 Clang 相比)

    MSVC 与 GCC Clang 的流 内部字符串和操作排序问题 大家好 我最近刚刚开始更认真地使用 MSVC 来完成我的一个跨平台项目 同时通过以下方式测试输出chainedSTD 流 IE 一系列的obj foo lt lt endl