小编wal*_*nut的帖子

应该通过std :: cin(gcc,clang disagree)将读取否定为无符号失败?

例如,

#include <iostream>

int main() {
  unsigned n{};
  std::cin >> n;
  std::cout << n << ' ' << (bool)std::cin << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

输入时-1,clang 6.0.0输出,0 0gcc 7.2.0输出4294967295 1.我想知道谁是对的.或者两者都是正确的标准没有指定这个?如果失败,我认为(bool)std::cin被评估为假.clang 6.0.0也输入失败-0.

c++ cin c++-standard-library language-lawyer c++17

31
推荐指数
1
解决办法
913
查看次数

在C ++ 17中的对象生存期之外调用非静态成员函数

以下程序在C ++ 17和更高版本中是否具有未定义的行为?

struct A {
    void f(int) { /* Assume there is no access to *this here */ }
};

int main() {
    auto a = new A;
    a->f((a->~A(), 0));
}
Run Code Online (Sandbox Code Playgroud)

C ++ 17保证a->f在评估A调用的参数之前先对对象的成员函数进行评估。因此,来自的间接->定义是明确的。但是在输入函数调用之前,将评估参数并结束A对象的生存期(但是请参见下面的编辑内容)。通话是否仍存在未定义的行为?是否可以通过这种方式在对象的生存期之外调用它的成员函数?

[expr.ref] /6.3.2的值类别a->f为prvalue ,[basic.life] / 7仅禁止对引用了生存期对象的glvalue进行非静态成员函数调用。这是否表示通话有效?(编辑:如评论中所讨论,我可能会误会[basic.life] / 7,它可能确实适用于此。)

如果我a->~A()delete anew(a) A(用#include<new>)替换析构函数调用,答案是否会改变?


关于我的问题的一些详尽的编辑和说明:


如果我将成员函数调用和析构函数/删除/放置新函数分成两个语句,我认为答案很明确:

  1. a->A(); a->f(0):UB,因为a在其生命周期之外会进行非静态成员调用。(不过请参见下面的编辑)
  2. delete a; a->f(0):同上
  3. new(a) …

c++ language-lawyer order-of-execution c++17 c++20

28
推荐指数
2
解决办法
884
查看次数

在自己的初始化程序中使用变量

C++20 标准草案的[basic.scope.pdecl]/1在注释中包含以下(非规范性)示例(合并拉取请求 3580之前的部分引用,请参阅此问题的答案):

unsigned char x = x;
Run Code Online (Sandbox Code Playgroud)

[...] x 用它自己的(不确定的)值初始化。

这实际上在 C++20 中有明确定义的行为吗?


通常T x = x;,由于x的值在初始化完成之前是不确定的,因此表单的自初始化具有未定义的行为。评估不确定的值通常会导致未定义的行为([basic.indent]/2),但在[basic.indent]/2.3中有一个特定的例外,它允许直接unsigned charunsigned char具有不确定值的左值初始化变量(导致使用不确定值初始化)。

这本身并不会因此导致不确定的行为,但会为其他类型T不属于无符号窄字符类型或std::byteint x = x;。这些注意事项也适用于 C++17 及之前的版本,另请参阅底部的链接问题。

然而,即使对于unsigned char x = x;,当前草案的[basic.lifetime]/7说:

类似地,在对象的生命周期开始之前 [...] 使用不依赖于其值的泛左值的属性是明确定义的。在以下情况下,程序具有未定义的行为:

  • 泛左值用于访问对象,或

  • [...]

这似乎意味着x示例中的that值只能在其生命周期内使用。

[basic.lifetime]/1说:

[...]

类型 T 的对象的生命周期在以下情况下开始:

  • [...] 和
  • 它的初始化(如果有)完成(包括空初始化)([dcl.init]),

[...]

因此x的生命周期仅在初始化完成后才开始。但是在引用的例子中 …

c++ initialization lifetime language-lawyer c++20

23
推荐指数
1
解决办法
637
查看次数

使用 std::call_once 抛出异常的错误

我试图从文档页面https://en.cppreference.com/w/cpp/thread/call_once运行示例,但它没有按预期工作。它会无限卡住。我想知道为什么会发生这种情况,或者它是否只是与某些特定编译器版本相关的错误。这是我用来运行程序https://repl.it/repls/UtterJubilantArchitects

#include <iostream>
#include <thread>
#include <mutex>

std::once_flag flag1, flag2;

void simple_do_once()
{
    std::call_once(flag1, [](){ std::cout << "Simple example: called once\n"; });
}

void may_throw_function(bool do_throw)
{
  if (do_throw) {
    std::cout << "throw: call_once will retry\n"; // this may appear more than once
    throw std::exception();
  }
  std::cout << "Didn't throw, call_once will not attempt again\n"; // guaranteed once
}

void do_once(bool do_throw)
{
  try {
    std::call_once(flag2, may_throw_function, do_throw);
  }
  catch (...) {
  }
}

int main()
{ …
Run Code Online (Sandbox Code Playgroud)

c++ libstdc++ c++11

13
推荐指数
1
解决办法
371
查看次数

复制和移动构造函数自动成为朋友吗?

当我们定义复制或移动构造函数时,我们可以访问另一个类的私有变量。C ++是否会friend自动使它们彼此交互?

例如:

my_str::my_str(my_str&& m) 
{
    size_ = m.size_; //accessing private variable another my_str class
    buff_ = m.buff_; //accessing private variable another my_str class
    m.buff_ = nullptr;
    m.size_ = 0;
}
Run Code Online (Sandbox Code Playgroud)

c++ friend-class

12
推荐指数
2
解决办法
998
查看次数

未指定的隐式对象创建

由于P0593 为低级对象操作隐式创建对象已被接受,因此现在可以在 C++20 中隐式创建对象。

具体而言,提案中引入的措辞允许某些操作(例如std::malloc)自动创建和启动某些类型的对象的生命周期,即所谓的隐式生命周期类型如果此类对象的引入会导致具有其他未定义行为的程序具​​有定义的行为。见[intro.object]/10

该草案现在进一步指出,如果可以隐式创建多个此类对象集以提供程序定义的行为,则未指定创建这些对象中的哪一个。(相关句子似乎没有出现在我可以访问的最后一个提案修订版中,R5,但在提交草案中。)

实际上是否有一个程序可以观察到这种隐式创建的对象集的选择?换句话说,是否有一个程序通过这个新规则定义了但未指定的行为,以便可以从输出推断出哪些类型的隐式对象(从多个可能的对象中)被创建?

还是这句话只是为了澄清抽象机器上的程序执行(没有可观察到的影响)?

c++ language-lawyer c++20

11
推荐指数
1
解决办法
313
查看次数

未指定的常量表达式值和 ODR

在三个文件中考虑这个程序:

// a.h

#include<iostream>

constexpr auto f() {
    int i = 0;
    auto l1 = [](int& j) { return ++j; };
    auto l2 = [](int& j) { return j*=2; };
    return l1(i) + l2(i);
}

template<auto V> struct constant {};

inline auto g() {
    constexpr auto x = f();
    std::ios_base::Init init; // Avoid possible initialization order issues
    std::cout << x;
    return constant<x>{};
}

static auto x = g();
inline auto y = g();
Run Code Online (Sandbox Code Playgroud)
// a.cpp

#include "a.h"
Run Code Online (Sandbox Code Playgroud)
// main.cpp

#include …
Run Code Online (Sandbox Code Playgroud)

c++ one-definition-rule language-lawyer c++17

10
推荐指数
1
解决办法
153
查看次数

使用空指针参数和不可能的后置条件构造标准异常

考虑以下程序:

#include<stdexcept>
#include<iostream>

int main() {
    try {
        throw std::range_error(nullptr);
    } catch(const std::range_error&) {
        std::cout << "Caught!\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

带有 libstdc++ 的 GCC 和 Clang 调用std::terminate并使用消息中止程序

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_S_construct null not valid
Run Code Online (Sandbox Code Playgroud)

使用 libc++ 段错误构建异常的 Clang。

神箭

编译器的行为是否符合标准?标准[diagnostics.range.error] (C++17 N4659)的相关部分确实说std::range_error有一个const char*构造函数重载,应该优先于const std::string&重载。该部分也没有说明构造函数的任何先决条件,而只说明了后置条件

后置条件strcmp(what(), what_­arg) == 0

如果what_arg是空指针,则此后置条件总是具有未定义的行为,那么这是否意味着我的程序也具有未定义的行为并且两个编译器的行为都一致?如果不是,应该如何阅读标准中这种不可能的后置条件?


再想一想,我认为这对我的程序来说一定意味着未定义的行为,因为如果不是,那么也将允许(有效)指针不指向以空字符结尾的字符串,这显然没有意义。

因此,假设这是真的,我想将问题更多地集中在标准如何暗示这种未定义的行为上。是否因为调用也具有未定义的行为或先决条件被简单地遗忘了后置条件的不可能性?


受到这个问题的启发。

c++ exception language-lawyer

9
推荐指数
1
解决办法
225
查看次数

On the term "(strict) aliasing violation" relating to class member access

This question refers to the current C++20 draft. The quoted passages have been slightly modified from previous standard iterations, but not in relevant ways as far as I know.

I am looking for clarification on the the terms "aliasing violation" or "strict aliasing violation".

My previous impression was that these terms refer specifically to violations of the standard paragraph [basic.lval]/11:

If a program attempts to access ([defns.access]) the stored value of an object through a …

c++ strict-aliasing language-lawyer reinterpret-cast

8
推荐指数
1
解决办法
141
查看次数

用户提供的 std::allocator 特化

::std命名空间中的类模板通常可以由程序专门用于用户定义的类型。我没有发现此规则的任何例外情况std::allocator

那么,我可以专攻std::allocator我自己的类型吗?如果我被允许,我是否需要提供std::allocator的主模板的所有成员,因为其中许多成员可以由std::allocator_traits(因此在 C++17 中被弃用)?

考虑这个程序

#include<vector>
#include<utility>
#include<type_traits>
#include<iostream>
#include<limits>
#include<stdexcept>

struct A { };

namespace std {
    template<>
    struct allocator<A> {
        using value_type = A;
        using size_type = std::size_t;
        using difference_type = std::ptrdiff_t;
        using propagate_on_container_move_assignment = std::true_type;

        allocator() = default;

        template<class U>
        allocator(const allocator<U>&) noexcept {}

        value_type* allocate(std::size_t n) {
            if(std::numeric_limits<std::size_t>::max()/sizeof(value_type) < n)
                throw std::bad_array_new_length{};
            std::cout << "Allocating for " << n << "\n";
            return static_cast<value_type*>(::operator new(n*sizeof(value_type)));
        }

        void …
Run Code Online (Sandbox Code Playgroud)

c++ allocator c++17

8
推荐指数
1
解决办法
301
查看次数