这个程序是否定义明确,如果没有,为什么呢?
#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的递归析构函数.我对吗?
为了给出我正在讨论的内容,下面的程序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
真正的动态类型?
考虑以下一对相互引用类型:
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)
最后,如果容器也不是微不足道的,例如(在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:我意识到这些课程在任何方面都不实用,因此语言律师标签.这里相关且稍微更实际的旧讨论: …
它是在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提交错误报告吗?
std::scoped_allocator_adaptor
到目前为止,在尝试使用gcc 4.7.0中实现的C++ 11时,我注意到C++ 11 FDIS定义了std::uses_allocator
for 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++教程都会使用这样的字符串(赋予或接受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)
甚至更可能,甚至可以写?
标准规定,在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++ 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
算术提取运算符对所有8个整数类型std::basic_istream
都有非虚拟重载(不列出字符,无论如何都是以不同的方式处理),并调用它num_get::get
,其中有6个具有单独的虚拟重载(缺少short和int的签名版本)
用于算术插入运算符std::basic_ostream
还具有所有8种整数类型的非虚拟重载,并呼吁num_put::put
,其中仅具有用于4种类型的虚拟过载,它们是long
,long long
以及它们的无符号的变体.对于较小的类型,插入运算符执行整数提升.
为什么在用户可扩展性方面存在差距呢?似乎不可能为每个整数类型提供用户定义的处理(例如,在iostream接口之上构建一个类型保留的序列化库),而且它是不对称的.它可以通过很少的努力实现.有没有权衡?
鉴于前缀一元运算符可以" 由一个没有参数的非静态成员函数或一个参数的非成员函数实现 "(§13.5.1[over.unary]/1),除了通常之外还有区别吗封装/代码重用设计原理适用于任何成员/非成员函数选择?
对于二元运算符,存在语义差异,因为非成员允许对其左侧操作数进行隐式转换.对于一元运算符似乎没有类似的东西,但标准将std::complex
一元否定运算符定义为非成员(第26.4.6节[complex.ops]),而一元std::valarray
和std::duration
一元否定运算符是成员(§26.6.2.6[valarray.unary],§20.11.5.3[time.duration.arithmetic]).有细微差别吗?
c++ ×10
c++11 ×6
locale ×2
allocator ×1
atomic ×1
destructor ×1
g++ ×1
iostream ×1
non-unicode ×1
overloading ×1