特定
struct S {
  SomeType single_element_in_the_struct;
};
这总是如此
sizeof(struct S) == sizeof(SomeType)
或者它可能依赖于实现?
看完这个讨论后,我意识到我几乎完全误解了这件事:)
由于C++抽象机器的描述不够严格(例如,与JVM规范进行比较),如果无法得到准确的答案,我宁愿希望得到关于合理"好"的规则的非正式澄清(非恶意) )实施应遵循.
标准中关于实现自由的第1.9部分的关键概念被称为as-if规则:
只要可以从程序的可观察行为中确定,结果就好像符合要求一样,实施可以自由地忽略本标准的任何要求.
根据标准(I引用n3092),术语"可观察行为"表示以下内容:
- 严格根据抽象机的规则来评估对易失性对象的访问.
- 在程序终止时,写入文件的所有数据应与根据抽象语义产生的程序执行的可能结果之一相同.
- 交互设备的输入和输出动态应以在程序等待输入之前提示输出实际传送的方式进行.构成交互设备的是实现定义的.
因此,粗略地说,应保留易失性访问操作和io操作的顺序和操作数; 实现可以在保存这些不变量的程序中进行任意更改(与抽象c ++机器的某些允许行为相比)
期望非恶意实现对操作进行足够广泛的处理是否合理(例如,来自用户代码的任何系统调用都被视为此类操作)?(例如,如果RAII包装器不包含挥发物,则编译器不会丢弃RAII互斥锁定/解锁)
"行为观察"应该从用户定义的c ++程序级别深入到库/系统调用中有多深?现在的问题是,当然,只有该库的调用不打算有从用户角度来看IO /挥发性接入(例如,作为新/删除操作),而且可能(通常如此)访问挥发,或在图书馆/系统IO 实现.应该从用户的角度来看,编译器将这类电话(并考虑副作用,如没有可观察到的),或从"库"的观点(以及考虑的副作用观察到的)?
如果我需要通过编译器,以防止一些代码消除,这是一个好的做法,是不会问上面的所有问题,并简单地增加(可能是假的)挥发性存取操作(换行需要挥发的方法的行动,并呼吁他们对挥发性情况我在任何情况下似乎可疑?
或者我完全错了,除了标准明确提到的情况(作为副本消除)之外,编译器不允许删除任何c ++代码
考虑两个指针
A* a; 
B* b;
A和B都是多态类.如何检查a和b是否指向同一个对象?
更确切地说,如果存在类型D的某个对象d,则指定a和b指向同一对象,使得*a和*b都在d的类层次结构中的某处.
我建议以下解决方案:
dynamic_cast<void*>(a) == dynamic_cast<void*>(b)
的确,根据标准,
dynamic_cast<void*>(v) 
产生"指向v.指向的最派生对象的指针(n3242.pdf:§5.2.7 - 7).如果两者的派生最多是同一个对象,则指针指向同一个对象.
从实际角度来看,我很确定它应该始终正常工作.但理论上,乍一看提议的平等似乎会产生假阳性,例如,如果b指向A的第一个成员(不是A的祖先).虽然实际上不可能为A及其成员获取相同的地址,因为A的虚拟表指针应位于此成员之前,因此该标准不强制要求虚拟表,也不对类布局说明任何内容.
所以,我的问题是:
从标准角度来看,建议的解决方案是否正确?
有关私人(受保护)继承或cv资格的任何警告吗?
有更好的解决方案吗?
[编辑]
我试图提供一些例子来说明一个相对复杂的场景.在这种情况下,动态横向铸造和静态铸造是模糊的.
 // proposed impplementation:
template<typename P, typename Q> 
bool test_ptrs(const P* p, const Q* q)
{
  return (dynamic_cast<const void*>(p) ==  dynamic_cast<const void*>(q));
}
struct Root
{
  virtual ~Root(){};
};
struct A: public Root // nonvirtually
{
};
struct B: public Root // nonvirtually
{
};
struct C: public A, B  // nonvirtual diamond started with Root
{
  Root …标准单元结构提供内部可变性,但只允许少数变异方法,如 set()、swap() 和 replace()。所有这些方法都会改变 Cell 的整个内容。但是,有时需要更具体的操作,例如,仅更改 Cell 中包含的部分数据。
所以我尝试实现某种通用 Cell,允许任意数据操作。操作由用户定义的闭包表示,该闭包接受单个参数 - &mut 对 Cell 内部数据的引用,因此用户自己可以决定如何处理 Cell 内部。下面的代码演示了这个想法:
use std::cell::UnsafeCell;
struct MtCell<Data>{
    dcell: UnsafeCell<Data>,
}
impl<Data> MtCell<Data>{
    fn new(d: Data) -> MtCell<Data> {
        return MtCell{dcell: UnsafeCell::new(d)};
    }
    fn exec<F, RetType>(&self, func: F) -> RetType where
        RetType: Copy,
        F: Fn(&mut Data) -> RetType 
    {
        let p = self.dcell.get();
        let pd: &mut Data;
        unsafe{ pd = &mut *p; }
        return func(pd);
    }
}
// test:
type MyCell = MtCell<usize>;
fn main(){ …我想听听各种意见如何在关键任务实时应用程序中安全地使用c ++.
更确切地说,可能可以创建一些宏/模板/类库来进行安全数据操作(密封溢出,zerodivides产生无穷大值或仅对特殊的"非零"数据类型进行除法),具有绑定检查和foreach循环的数组,安全的智能指针(例如类似于boost shared_ptr)甚至安全的多线程/分布式模型(消息传递和轻量级进程,如在Erlang语言中定义的).
然后我们禁止一些危险的c/c ++构造,如原始指针,一些原始类型,本机"新"操作符和本机c/c ++数组(对于应用程序员,当然不是库编写者).理想情况下,我们应该创建一个特殊的预处理器/检查器,至少我们必须有一些正式的检查程序,可以使用某些工具或某些人手动应用于源.
所以,我的问题:
1)是否有任何现有的图书馆/项目利用这样的想法?(嵌入式c ++显然不是理想的那种)?
2)这根本不是一个好主意吗?或者它可能只对原型化另一种时髦的语言有用吗?或者它完全无法使用?
3)关于此事的任何其他想法(或链接)也欢迎
对不起,如果这个问题实际上不是一个问题,offtopic,重复等,但我没有找到更合适的地方问它
如果new []表达式用于创建具有析构函数的对象数组,则可能无法正确地对齐数组中的对象
#include <stdint.h>
#include <stdio.h>
#pragma pack(8)
struct A{
  int64_t i;
  char dummy;
  ~A(){}
};
int main(){
  A* pa= new A[2];
  printf("sizeof(A)= %d, pointer= %p", sizeof(A), pa);
}
(我使用VC++ 2010 express构建32位目标)
输出(在我的电脑上)是:
sizeof(A)= 16 pointer= 00344f4c
(sizeof(A)= 16表示编译器解释了A的对齐要求,并且结构填充了7个字节[编辑:__ alignof(A)也返回8])
我明白为什么会发生这种情况:new []需要存储数组长度,并且它为此目的使用前4个字节的已分配内存,然后它在没有适当填充的情况下分配数组本身.
从实际的角度来看,这种行为肯定很差,但它是否符合标准?
我想将一些对象暴露为具有stl样式操作可能性的抽象容器(for_each循环,迭代器)和隐藏容器实现细节.
性能问题无关紧要(复制"通用"迭代器时虚拟调用甚至内存分配都是可以接受的).
我将编写一个带有纯虚函数的抽象容器接口(+容器上的"通用"迭代器)和一个用于stl顺序容器的实现适配器.
但也许有用于此目的的有用的现有库?
或者这完全是一个坏主意?
例如,在Winnt.h中定义了众所周知的CONTAINING_RECORD()宏:
#define CONTAINING_RECORD(address, type, field) ((type *)( \
                                              (PCHAR)(address) - \
                                              (ULONG_PTR)(&((type *)0)->field)))
或者在FreeBSD中:
#define CONTAINING_RECORD(addr, type, field)    \
      ((type *)((vm_offset_t)(addr) - (vm_offset_t)(&((type *)0)->field)))
或者在Linux中:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({                      \
      const typeof(((type *)0)->member) * __mptr = (ptr);     \
      (type *)((char *)__mptr - offsetof(type, member)); })
而且,当然,在全世界许多其他地方.
但是,我怀疑它们是否符合标准.
提升源(boost_1_48_0/boost/intrusive/detail/parent_from_meber.hpp)让我失望 - 他们有3个#ifdef PARTICULAR_COMPILER案例:
template<class Parent, class Member>
inline std::ptrdiff_t offset_from_pointer_to_member(const Member Parent::* ptr_to_member)
{
   //The implementation of a pointer to member is compiler dependent.
   #if …有没有支持可伸缩数据库的 Prolog 实现?我的意思是,当 prolog 引擎通过此谓词调用回溯时,数据库会自动撤回由 assert() 谓词调用插入的事实?换句话说,我想要在回溯时“自动”隐式撤回。
类似的东西可以表达为
my_assert(Fact):- assert(Fact).
my_assert(Fact):- retract(Fact), fail.
但这在通过切割回溯时无法正常工作(!)
或者这个目标可以通过使用 Prolog 的“tabled”风格以某种方式实现?
我看不出有任何理由为“本机”CPU 积分增加额外开销,但我可能错了,所以我想听听社区的意见
我真正的问题涉及某种相对罕见变化但经常被阅读的链接列表(类似于典型的 RCU 用例)。这个想法是为只读操作提供 2 种访问模式:如果结构现在正在改变(完整的无锁算法),则使用第一种模式,“平静”情况下使用第二种轻量级模式(具有非原子列表遍历)。对于第二种(轻量级)情况,我将使用具有 memory_order_relaxed 的原子负载,但如果它太昂贵,我需要做一些解决方法(缓存非原子变量中的原子值,或以某种方式模拟建议的 memory_order_nonatomic http ://www.open-std.org/jtc1/sc22/wg14/www/docs/n1446.htm等)
我知道答案取决于原子实现(和 CPU),但我希望实现应该表现得合理:)
换句话说,我可以将void*指针重新解释(而不是转换!)作为某种结构类型的void*指针(假设该指针确实包含正确转换的有效结构地址)
实际上,在以下情况下我很有趣:
typedef struct void_struct void_struct_t;
typedef somestruct
{ 
    int member;
    // ... other members ...
}somestruct_t;
union 
{
    void*          pv; 
    void_struct_t* pvs; 
    somestruct_t*  ps; 
}u;
somestruct_t s={};
u.pv= &s;
u.ps->member=1; // (Case 1)  Ok? unspecified? UB? 
u.pvs=(void_struct_t*)&s;
u.ps->member=1;  // (Case 2) )Ok?
我在C11标准中发现的情况1相当令人失望:
§6.2.5
28指向void的指针应具有与>指向字符类型的指针相同的表示和对齐要求。相似地,指向兼容类型的合格或不合格版本的指针应具有相同的表示和对齐要求。所有指向结构类型的指针应具有相同的表示和对齐要求。所有指向联合类型的指针应具有相同的表示和对齐要求。指向其他类型的指针不必具有相同的表示或对齐要求。
不过,情况2似乎有效,但我不确定100%...
这个问题主要是面向C的,但是我对C ++也很感兴趣(我希望代码在由C ++编译器编译时将是有效的)。老实说,我在C ++ 11标准中发现的更少,所以即使情况2对我来说也值得怀疑...但是,可能是我遗漏了一些东西。
[编辑]这个问题背后的真正问题是什么?
我有一组(可能很大)定义为结构的类型。对于每种类型,我需要定义一个伴随类型:
typedef struct companion_for_sometype
{
  sometype* p_object;
  // there are also other members
}companion_for_sometype;
显然,伴随类型将是C ++中的模板,但是我需要C的解决方案(更确切地说,是“干净的C”,即C89和C ++的交集,因为我希望我的代码也是有效的C ++代码)。
幸运的是,即使在C语言中也不是问题,因为我可以定义一个宏
DECLARE_COMPANION(type_name) typedef struct companion_for_##type_name …c++ ×9
c ×4
atomic ×1
c++11 ×1
c11 ×1
containers ×1
dynamic-cast ×1
embedded ×1
prolog ×1
real-time ×1
rust ×1
stl ×1
visual-c++ ×1