是否有任何C或C++编译器为volatile变量实现"积极"的内存一致性模型?通过"积极"一致性模型,我的意思是伴随所有写入volatile生成代码中具有内存障碍的变量.
AFAIK,这是IA64(Itanium)平台上C或C++编译器的习惯行为.x86怎么样?是否有一个编译器实现(或可以配置实现)类似于Itanium的方法来处理volatilex86平台上的变量?
编辑:我正在查看VS 2005生成的代码(在阅读注释后),并且在访问volatile变量时我没有看到任何类似于任何内存屏障的内容.由于MESIF(英特尔)和MOESI(AMD)缓存协议,这对于确保单CPU多核x86平台上的内存一致性非常好.
但是,在多CPU SMP x86平台上,这似乎不够.SMP平台在生成的代码中需要内存屏障,以确保CPU之间的内存一致性.我错过了什么?当微软宣称他们已经拥有volatile变量的获取释放语义时,他究竟是什么意思呢?
我想知道使std::list<>::splice引用新子容器中的子序列的迭代器无效的原因是什么.这看起来有点不合逻辑,特别是在标准std::container::swap规格方面.根据语言标准std::container::swap 不会使任何迭代器无效.这是一个非常合理的实用规范.但是,我会说这std::list<>::splice也会从保留迭代器的行为中获益匪浅.
我理解可能存在基于迭代器可达性等概念的纯粹学术考虑.但同时splice也是一种std::list特定的操作,这意味着为它提供定制的规范可能不会对其造成严重的概念损害.一般的STL设计.
那是什么?它会使一些std::list我认识不到的实际实施变得非法或过于复杂吗?
在我的实验中这个表达
double d = strtod("3ex", &end);
Run Code Online (Sandbox Code Playgroud)
初始化d,3.0并将end指针放在'e'输入字符串中的字符处.这正如我所期望的那样.该'e'字符可能看起来是指数部分的开头,但由于缺少实际的指数值(6.4.4.2要求),因此'e'应将其视为完全独立的字符.
但是,当我这样做的时候
double d;
char c;
sscanf("3ex", "%lf%c", &d, &c);
Run Code Online (Sandbox Code Playgroud)
我注意到,sscanf消耗都'3'与'e'该%lf格式说明.变量d接收3.0价值.变量以其c结尾'x'.这看起来很奇怪有两个原因.
首先,由于语言规范strtod在描述%f格式说明符的行为时引用,我直观地期望%lf以相同的方式处理输入strtod(即选择与终止点相同的位置).但是,我知道历史scanf上应该只返回一个字符回输入流.这限制了任何前瞻scanf可以通过一个角色执行的距离.上面的例子需要至少两个字符前瞻.所以,让我们说,我接受这样的事实%lf消耗都'3'与'e'从输入流.
但后来我们遇到了第二个问题.现在sscanf必须将其转换"3e"为类型double."3e"不是浮点常量的有效表示(同样,根据6.4.4.2,指数值不是可选的).我希望sscanf看待这个输入为错误:在终止%lf转换,返回0和离开d …
考虑这个代码示例
template <typename T> struct S { T t; };
template <class T> void foo(const S<T> &v)
{
bar(v.t);
}
namespace N
{
struct A {};
}
void bar(const N::A &a) {}
int main()
{
S<N::A> a;
foo(a);
}
Run Code Online (Sandbox Code Playgroud)
代码无法在GCC和Clang中编译,因为常规查找和ADL都无法解析bar来自的调用foo.这是完全可以预期的,因为bar调用的关联命名空间列表就是这样N.不包括全局命名空间,找不到全局命名空间bar.一切都应该如此.
但是,如果我将其更改为
template <typename T> struct S { T t; };
template <class T> void foo(const S<T> &v)
{
+v.t;
}
namespace N
{
struct A {};
}
void operator +(const …Run Code Online (Sandbox Code Playgroud) c++ gcc operator-overloading language-lawyer argument-dependent-lookup
由于重载解析不明确,此代码示例无法编译
void g(char (&t)[4]) {}
void g(char *t) {}
int main()
{
char a[] = "123";
g(a);
}
Run Code Online (Sandbox Code Playgroud)
仔细阅读重载解析规则可以清楚为什么失败。这里没有问题。
如果我们正式将其改造为模板版本
template <typename T> void g(T (&t)[4]) {}
template <typename T> void g(T *t) {}
int main()
{
char a[] = "123";
g(a);
}
Run Code Online (Sandbox Code Playgroud)
它将继续“按预期”运行,并因同样性质的模糊性而失败。到目前为止,一切都很好。
然而,下面的版本编译没有任何问题并选择了第二个重载
template <typename T> void g(T &t) {}
template <typename T> void g(T *t) {}
int main()
{
char a[] = "123";
g(a);
}
Run Code Online (Sandbox Code Playgroud)
如果我们注释掉第二个重载,第一个重载将成功地与推导为T一起使用char [4],即模板参数推导按第一个版本的预期工作,有效地使其相当于void g(char (&t)[4])。因此,乍一看,第三个示例的行为应该与前两个示例相同。
然而,它可以编译。在第三种情况下,什么[模板]重载解析规则可以挽救局面并指示编译器选择第二个重载?为什么它更喜欢数组到指针的转换而不是直接引用绑定?
PS …
我需要从GCC for Linux编译的C程序中回答一个基本问题:当前正在使用多少进程堆(由分配malloc)以及如果有空闲堆阻塞了多少.标准库的GNU实现具有mallinfo准确报告我需要的功能,但它只能用于32位配置,而AFAIK,没有64位等效的功能(BTW,谁知道为什么?).
我在Linux上使用GCC,所以我需要这个用于Linux.但我认为堆对系统是不透明的,因此回答这个问题的唯一方法是使用标准库实现提供的方法.
在Windows平台上的MSVC实现中,没有相应的mallinfo功能,但有所谓的堆行走功能,它允许通过迭代堆中的所有块来计算必要的信息.AFAIK,GNU C库中没有堆行走接口.(在那儿?).
那么,再说一次,我在GCC做什么?它不一定非常有效,这意味着前面提到的基于堆步行的方法对我来说非常好.我如何知道GCC使用了多少堆以及有多少空闲?我可以尝试安装malloc-hooks并"手动"跟踪大小,虽然我不知道如何在mallinfo.arena不使用的情况下确定当前堆竞技场大小(请参阅参考资料)mallinfo.
请考虑以下简单示例
#include <string>
#include <sstream>
#include <iomanip>
using namespace std;
int main() {
string str = "string";
istringstream is(str);
is >> setw(6) >> str;
return is.eof();
}
Run Code Online (Sandbox Code Playgroud)
乍一看,由于显式宽度由setw操纵器指定,我希望>>操作符在从输入流成功提取所请求的字符数后完成读取字符串.我没有看到它尝试提取第七个字符的任何直接原因,这意味着我不希望流进入eof状态.
当我在MSVC++下运行这个例子时,它按照我的预期工作:读取后流保持良好状态.但是,在GCC中,行为是不同的:流最终处于eof状态.
语言标准,它为此版本的>>运算符提供以下完成条件列表
- 存储n个字符;
- 文件结束发生在输入序列上;
- 对于下一个可用的输入字符c,isspace(c,is.getloc())为true.
鉴于上述情况,我认为>>运营商没有任何理由将流驱动到eof上述代码中的状态.
然而,这是什么>>运营商在GCC库的实现看起来像
...
__int_type __c = __in.rdbuf()->sgetc();
while (__extracted < __n
&& !_Traits::eq_int_type(__c, __eof)
&& !__ct.is(__ctype_base::space,
_Traits::to_char_type(__c)))
{
if (__len == sizeof(__buf) / sizeof(_CharT))
{
__str.append(__buf, sizeof(__buf) / sizeof(_CharT)); …Run Code Online (Sandbox Code Playgroud) 以下代码
#include <array>
void foo(const std::array<int, 42> &a)
{
constexpr size_t S = a.size();
}
int main() {}
Run Code Online (Sandbox Code Playgroud)
在GCC中编译正常,但无法在clang中编译以下错误消息
main.cpp:5:28: error: constexpr variable 'S' must be initialized by a constant expression
constexpr size_t S = a.size();
^~~~~~~~
Run Code Online (Sandbox Code Playgroud)
与此同时,很多constexpr关于SO问题的帖子似乎暗示铿锵经常有更好(更迂腐?)的支持constexpr.那么,在这种情况下哪个编译器是正确的?
请注意,一旦参考参数被pass-by-value参数替换,两个编译器都乐于接受代码.
考虑以下问题.
我们给出了一组属于两个类的元素:红色或蓝色.我们必须重新排列数组的元素,以便所有蓝色元素首先出现(并且所有红色元素都会出现).必须以稳定的方式完成重新排列,这意味着必须保留蓝色元素的相对顺序(红色元素的相对顺序).
是否有一个聪明的算法可以就地执行上述重新排列?
当然,非现场解决方案很简单.
一个明显的就地解决方案是将任何稳定的排序算法应用于阵列.然而,在阵列上使用完整的排序算法直观地感觉就像是一种过度杀伤,特别是考虑到我们只处理两类元素这一事实.
任何想法都非常感激.
在N4659中16.3.3.1隐式转换序列说
10如果存在几个不同的转换序列,每个转换序列都将自变量转换为参数类型,则与参数关联的隐式转换序列被定义为唯一的转换序列,称为歧义转换序列。为了对16.3.3.2中所述的隐式转换序列进行排名,歧义转换序列被视为与其他任何用户定义的转换序列都没有区别的用户定义的转换序列[注意:此规则可防止函数变为非-viable,因为其参数之一的转换顺序不明确。]如果选择使用歧义转换顺序的函数作为最佳可行函数,则该调用将格式错误,因为该调用中参数之一的转换是模棱两可的。
(当前草案的相应部分为12.3.3.1)
该规则的预期目的是什么,以及引入的歧义转换序列的概念是什么?
文本中提供的注释指出,此规则的目的是“防止功能由于其参数之一的转换顺序不明确而变得不可行 ”。嗯...这实际上是指什么?可行功能的概念在文档的前面部分中定义。它根本不取决于转换的歧义性(每个参数的转换必须存在,但不必明确)。而且似乎没有提供可行的功能以某种方式在以后“变得不可行”的规定(既不是出于某种模棱两可,也不是因为其他原因)。列举了可行的功能,它们相互竞争,成为“最佳”如果有一个“获胜者”,则解决方案成功。在此过程中的任何时候,可行的功能都可能(或需要)变成不可行的功能。
上述段落中提供的示例不是很有启发性(即尚不清楚上述规则在该示例中扮演什么角色)。
这个简单的例子最初引发了这个问题
struct S
{
operator int() const { return 0; };
operator long() const { return 0; };
};
void foo(int) {}
int main()
{
S s;
foo(s);
}
Run Code Online (Sandbox Code Playgroud)
让我们在这里机械地应用上述规则。foo是可行的功能。从参数类型S到参数类型有两个隐式转换序列int:S -> int和S -> long -> int。这意味着,根据上述规则,我们必须将它们“打包”成单个模糊的转换序列。然后我们得出结论,这foo是最好的可行功能。然后我们发现它使用了我们不明确的转换序列。因此,根据上述规则,代码格式错误。
这似乎没有任何意义。这里的自然期望是,S …
c++ conversion-operator language-lawyer overload-resolution implicit-conversion