小编Cub*_*bbi的帖子

析构函数可以递归吗?

这个程序是否定义明确,如果没有,为什么呢?

#include <iostream>
#include <new>
struct X {
    int cnt;
    X (int i) : cnt(i) {}
    ~X() {  
            std::cout << "destructor called, cnt=" << cnt << std::endl;
            if ( cnt-- > 0 )
                this->X::~X(); // explicit recursive call to dtor
    }
};
int main()
{   
    char* buf = new char[sizeof(X)];
    X* p = new(buf) X(7);
    p->X::~X();  // explicit call to dtor
    delete[] buf;
}
Run Code Online (Sandbox Code Playgroud)

我的推理:虽然两次调用析构函数是未定义的行为,但按照12.4/14,它的确如此:

如果为生命周期结束的对象调用析构函数,则行为未定义

这似乎并没有禁止递归调用.当对象的析构函数正在执行时,对象的生命周期尚未结束,因此再次调用析构函数不是UB.另一方面,12.4/6说:

执行body [...]后,类X的析构函数调用X的直接成员的析构函数,X的直接基类的析构函数[...]

这意味着在从析构函数的递归调用返回之后,将调用所有成员和基类析构函数,并在返回到上一级递归时再次调用它们将是UB.因此,没有基数且只有POD成员的类可以具有不带UB的递归析构函数.我对吗?

c++ destructor standards-compliance

50
推荐指数
3
解决办法
6995
查看次数

transform_primary()和collat​​e_byname()

为了给出我正在讨论的内容,下面的程序true在使用clang ++/libc ++编译时正确打印

#include <iostream>
#include <regex>
int main()
{
    std::locale::global(std::locale("en_US.UTF-8"));
    std::wstring str = L"AÀÁÂÃÄÅaàáâãäå";
    std::wregex re(L"[[=a=]]*", std::regex::basic);
    std::cout << std::boolalpha << std::regex_match(str, re) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

但是,我不太明白std::regex_traits::transform_primary()标准中的描述(通过它[=a=]来处理).引用28.7 [re.traits]/7:

if typeid(use_facet<collate<charT> >) == typeid(collate_byname<charT>)和返回的sort键的形式collate_byname<charT>::transform(first, last)是已知的并且可以转换为主排序键然后返回该键,否则返回一个空字符串.

原来的建议解释说,这个标准regex_traits::transform_primary()如果只能工作collate在充满语言环境方面不是由用户(这是它能够知道如何转换结果的唯一方式取代collate::transform()以等价键).

我的问题是,typeid标准中的比较应如何确保?这是否意味着所有系统提供的方面都脱离了语言环境并use_facet具有_byname真正的动态类型?

c++ locale c++11

24
推荐指数
1
解决办法
709
查看次数

初始化相互引用的对象

考虑以下一对相互引用类型:

struct A;
struct B { A& a; };
struct A { B& b; };
Run Code Online (Sandbox Code Playgroud)

这可以通过GCC,Clang,Intel,MSVC中的聚合初始化来初始化,但不能通过SunPro来初始化,因为SunPro坚持要求用户定义的ctors.

struct {A first; B second;} pair = {pair.second, pair.first};
Run Code Online (Sandbox Code Playgroud)

这个初始化合法吗?

更详细的演示:http://ideone.com/P4XFw

现在,听从Sun的警告,用户定义的构造函数的类怎么样?以下适用于GCC,clang,Intel,SunPro和MSVC,但它是否合法?

struct A;
struct B { A& ref; B(A& a) : ref(a) {} };
struct A { B& ref; A(B& b) : ref(b) {} };

struct {B first; A second;} pair = {pair.second, pair.first};
Run Code Online (Sandbox Code Playgroud)

演示:http://ideone.com/QQEpA

最后,如果容器也不是微不足道的,例如(在G ++,Intel,Clang(带警告)中工作,但不是MSVC(初始化器中未知的"配对")或SunPro("配对不是结构")

std::pair<A, B> pair(pair.second, pair.first);
Run Code Online (Sandbox Code Playgroud)

从我所看到的情况来看,§3.8[basic.life]/6禁止在生命周期开始之前访问非静态数据成员,但是对于第二次"对"第二次"访问"的左值评估是什么?如果是,那么这三个初始化都是非法的吗?另外,§8.3.2[dcl.ref]/5说"引用应该被初始化以引用一个有效的对象",这可能使所有三个都是非法的,但也许我错过了一些东西,编译器接受这个是有原因的.

PS:我意识到这些课程在任何方面都不实用,因此语言律师标签.这里相关且稍微更实际的旧讨论: …

c++ language-lawyer

19
推荐指数
1
解决办法
792
查看次数

std :: atomic_compare_exchange_weak线程不安全吗?

它是在cppreference atomic_compare_exchange Talk页面上提出的,现有的实现std::atomic_compare_exchange_weak 用非原子比较指令计算CAS的布尔结果,例如

    lock
    cmpxchgq   %rcx, (%rsp)
    cmpq       %rdx, %rax
Run Code Online (Sandbox Code Playgroud)

哪个(编辑:为红鲱道歉)

打破CAS循环,例如Concurrency in Action的清单7.2:

while(!head.compare_exchange_weak(new_node->next, new_node);
Run Code Online (Sandbox Code Playgroud)

规范(29.6.5 [atomics.types.operations.req]/21-22)似乎暗示比较的结果必须是原子操作的一部分:

效果:原子比较......

返回:比较的结果

但它实际上是否可以实现?我们应该向供应商或LWG提交错误报告吗?

c++ atomic c++11

19
推荐指数
2
解决办法
1875
查看次数

为什么元组有uses_allocator但是对没有?

std::scoped_allocator_adaptor到目前为止,在尝试使用gcc 4.7.0中实现的C++ 11时,我注意到C++ 11 FDIS定义了std::uses_allocatorfor tuples(20.4.2.8[tuple.traits])的特化,但是没有定义对,尽管出于所有其他目的,对看起来和行为就像元组(他们的专长std::get,std::tuple_size等等).

在进一步阅读中,介绍这些东西的N2554也定义了对的allocator_arg构造函数和特化uses_allocator(第23-24页).

他们为什么要成对掉队?有没有其他方法可以使用我看不到的,或者这是否有一些赞成元组的对折旧?

我的测试代码是:

// myalloc is like std::allocator, but has a single-argument
// constructor that takes an int, and has NO default constructor
typedef std::vector<int, myalloc<int>> innervector_t;
typedef std::tuple<int, innervector_t> elem_t;
typedef std::scoped_allocator_adaptor<myalloc<elem_t>, myalloc<int>> Alloc;
Alloc a(1,2);
std::vector<elem_t, Alloc> v(a);
v.resize(1);                  // uses allocator #1 for elements of v
// the following line fails to compile if pair is …
Run Code Online (Sandbox Code Playgroud)

c++ allocator c++11

12
推荐指数
1
解决办法
697
查看次数

如何在算法中使用带有默认参数的重载函数?

我知道常见问题的答案如何指定指向重载函数的指针?:使用赋值或使用强制转换,并且每个其他C++教程都会使用这样的字符串(赋予或接受static_cast):

transform(in.begin(), in.end(), back_inserter(out), (int(*)(int)) std::toupper);
Run Code Online (Sandbox Code Playgroud)

或者像这样:

int (*fp)(int) = std::toupper;
transform(in.begin(), in.end(), back_inserter(out), fp);
Run Code Online (Sandbox Code Playgroud)

它整齐地选择了<cctype>过载std::toupper.

但这引出了一个问题:如何<locale>以类似的方式选择过载?

char (*fp2)(char, const std::locale&) = std::toupper;
transform(in.begin(), in.end(), back_inserter(out), fp2);
// error: too few arguments to function
Run Code Online (Sandbox Code Playgroud)

或者,更实际地,考虑有人试图std::stoi在算法中使用C++ 11 将字符串向量转换为整数向量:stoi有两个重载(string/ wstring),每个重载两个额外的默认参数.

假设我不想显式绑定所有这些默认值,我相信如果不在辅助函数或lambda中包含这样的调用就不可能这样做.是否有一个提升包装或TMP魔术以完全通用的方式为我做这件事?一个包装器可以call_as<char(char)>(fp2),call_as<int(const std::string&)>(std::stoi)甚至更可能,甚至可以写?

c++ overloading default-arguments c++11

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

将braced-init-list赋值给数组是否正确?

标准规定,在5.17/9之下

braced-init-list可能出现在右侧
- 对标量的赋值[...]
- 由用户定义的赋值运算符[...]定义的赋值

在GCC 4.5.1-pre9999中,我可以编译它(使用-std = c ++ 0x,NOT -std = gnu ++ 0x)

#include <iostream>

int main()
{
        int test[] = {1,2,3};
        std::cout << test[0] << test[1] << test[2];
        test = {4,5,6};
        std::cout << test[0] << test[1] << test[2] << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

它打印出来123456.GCC在这里是否正确?

c++ g++ standards-compliance language-lawyer c++11

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

libc ++ vs VC++:可以使用wstring_convert完成非UTF转换吗?

在C++ 11的std::wstring_convert作品极大*为标准的UTF-8 < - > UTF-16/UCS2/UCS4转换.但是,当我尝试使用不是from的facet实例化wstring_convert或wbuffer_convert时<codecvt>,它没有按预期工作:

// works as expected
std::wstring_convert<std::codecvt_utf8<wchar_t>> ucs4conv;

// Now, by analogy, I want to try this:
std::wstring_convert<std::codecvt<wchar_t, char, std::mbstate_t>> gbconv(
        new std::codecvt_byname<wchar_t, char, std::mbstate_t>("zh_CN.gb18030"));
Run Code Online (Sandbox Code Playgroud)

Clang ++错误地说"在~wstring_convert中调用codecvt <>的受保护的析构函数"

Visual Studio允许它(尽管它缺少该语言环境,但这是另一个故事),因为它的wstring_convert将facet指针的生命周期管理作为成员的一个区域设置对象进行处理,并且locales知道如何删除指向所有facet的指针.

Visual Studio是正确的,libc ++是错误的吗?

*在clang ++ - 2.9/libc ++ - svn和Visual Studio 2010 EE SP1中实现,以下示例适用于两者,但不是在GCC中,遗憾的是:https://ideone.com/hywz6

c++ non-unicode c++11

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

为什么num_get和num_put不对称?

算术提取运算符对所有8个整数类型std::basic_istream都有非虚拟重载(不列出字符,无论如何都是以不同的方式处理),并调用它num_get::get,其中有6个具有单独的虚拟重载(缺少short和int的签名版本)

用于算术插入运算符std::basic_ostream还具有所有8种整数类型的非虚拟重载,并呼吁num_put::put,其中仅具有用于4种类型的虚拟过载,它们是long,long long以及它们的无符号的变体.对于较小的类型,插入运算符执行整数提升.

为什么在用户可扩展性方面存在差距呢?似乎不可能为每个整数类型提供用户定义的处理(例如,在iostream接口之上构建一个类型保留的序列化库),而且它是不对称的.它可以通过很少的努力实现.有没有权衡?

c++ locale iostream

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

一元减负荷:会员还是非会员?

鉴于前缀一元运算符可以" 由一个没有参数的非静态成员函数或一个参数的非成员函数实现 "(§13.5.1[over.unary]/1),除了通常之外还有区别吗封装/代码重用设计原理适用于任何成员/非成员函数选择?

对于二元运算符,存在语义差异,因为非成员允许对其左侧操作数进行隐式转换.对于一元运算符似乎没有类似的东西,但标准将std::complex一元否定运算符定义为非成员(第26.4.6节[complex.ops]),而一元std::valarraystd::duration一元否定运算符是成员(§26.6.2.6[valarray.unary],§20.11.5.3[time.duration.arithmetic]).有细微差别吗?

c++ operator-overloading

6
推荐指数
1
解决办法
711
查看次数