在C++ 11标准,为什么服用nullptr是不允许的,而一个地址,我不明白其中的道理被允许携带自己的std :: nullptr_t实例的地址.除了nullptr是保留关键字这一事实之外,是否有任何指定的推理作出此决定?
仅仅因为它让我很开心,我试图用以下函数环绕这个限制:
decltype(nullptr)* func(const decltype(nullptr) &nref) noexcept
{
return const_cast<decltype(nullptr)*>(reinterpret_cast<const decltype(nullptr)*>(&nref));
}
Run Code Online (Sandbox Code Playgroud)
我不得不在参数上使用reinterpret_cast,因为没有它我得到了歇斯底里的错误:
error: invalid conversion from 'std::nullptr_t*' to 'std::nullptr_t*' [-fpermissive]
Run Code Online (Sandbox Code Playgroud)
当我通过直接传递nullptr来调用此函数时,每次都会得到一个不同的地址.是否为nullptr动态分配地址及时进行比较等?或者(可能更有可能)编译器可能强制执行底层对象的临时副本?
当然,这些都不是至关重要的信息,我只是觉得有趣的是为什么要实施这一特定的限制(以及随后为什么我会看到我的行为).
这个答案引用了N4082,它表明即将进行的更改std::shared_ptr将允许两者T[]和T[N]变体:
不同于
unique_ptr用于阵列部分特,都shared_ptr<T[]>和shared_ptr<T[N]>将是有效的,都将导致delete[]被称为对象的管理的阵列上.Run Code Online (Sandbox Code Playgroud)template<class Y> explicit shared_ptr(Y* p);要求:
Y应为完整类型.表达式delete[] p,当T是数组类型时,或者delete p,当T不是数组类型时,应该是格式良好的,应该具有良好定义的行为,并且不应抛出异常.如果T是U[N],Y(*)[N]应转换为T*; 当T是U[],Y(*)[]应转变成T*; 否则,Y*应可转换为T*.
除非我弄错了,Y(*)[N]否则只能通过获取数组的地址来形成,这显然不能被a拥有或删除shared_ptr.我也没有看到任何N以任何方式强制使用托管对象大小的指示.
允许T[N]语法的动机是什么?它是否产生任何实际效益,如果是,它是如何使用的?
由于标准的措辞,C++中的静态类成员给我带来了一点混乱:
9.4.2静态数据成员 [class.static.data]
在类定义中声明静态数据成员不是定义......
但是,constexpr需要在其声明中初始化(AFAIK,无法从标准中找到引用)(例如,在类定义中).
由于constexpr的限制,我实际上已经忘记了在类之外定义静态成员的必要条件,直到我尝试访问静态constexpr数组.这个相关问题提供了定义数组成员的正确方法,但我对类模板中对此定义的含义感兴趣.
这就是我最终得到的结果:
template<typename T>
class MyClass
{
private:
static constexpr std::size_t _lut[256] = { /* ... */ };
T _data;
public:
static constexpr std::size_t GetValue(std::size_t n) noexcept
{
return _lut[n & 255];
}
// ...
};
template<typename T>
constexpr std::size_t MyClass<T>::_lut[256];
Run Code Online (Sandbox Code Playgroud)
这是正确的语法吗?特别是在定义中使用模板感觉很尴尬,但GCC似乎正确地将所有内容联系起来.
作为后续问题,是否应该类似地定义非数组静态constexpr成员(模板定义在类外)?
C++17§10.1.5/ 1指出:
的
constexpr说明符将只应用于一个变量或变量模板的定义或功能或功能模板的声明.使用说明constexpr符声明的函数或静态数据成员 隐式地是内联函数或变量(10.1.6).如果函数或函数模板的任何声明都有一个constexpr说明符,那么它的所有声明都应该包含说明constexpr符.
因为类似的段落已在标准中存在C++ 11(§7.1.5/ 1),这是在引述由理查德·史密斯评论,其中他争辩说,C++标准并没有要求constexpr说明符之间匹配声明和变量的定义.在上段的最后一句明确要求constexpr符横跨匹配功能和函数模板的声明,但并没有提及变量声明.
§10.1.5/ 9指出:
constexpr对象声明中使用的说明符将对象声明为const.这样的对象应具有文字类型并应初始化.在任何constexpr变量声明中,初始化的完整表达式应为常量表达式(8.20).
当然,如果我们有一个单独的声明和定义,它们都需要匹配const,无论constexpr指定符是否需要匹配.
§12.2.3.2/ 2-3说:
2在其类定义中声明非内联静态数据成员不是定义,并且可能是除cv 之外的不完整类型
void.未在类定义中内联定义的静态数据成员的定义应出现在包含成员类定义的命名空间范围内.在命名空间作用域的定义中,静态数据成员的名称应使用::运算符通过其类名限定.静态数据成员定义中的初始化表达式在其类的范围内(6.3.7).3如果非易失性非内联
const静态数据成员具有整数或枚举类型...如果使用说明constexpr符声明成员,则可以在没有初始化程序的命名空间范围内重新声明该成员 (此用法已弃用;请参阅D.1 ).其他静态数据成员的声明不应指定大括号或等于初始化器.
§D.1/ 1内容如下:
为了与先前的C++国际标准兼容,
constexpr可以在类外部冗余地重新声明静态数据成员而不使用初始化程序.不推荐使用此用法.
从中我们可以收集到,如果使用说明符声明成员constexpr,则命名空间范围定义是多余的, …
就在昨晚,我第一次遇到了好奇的Duff设备.我一直在做一些阅读,我不认为这是令人生畏的理解.我很好奇的是奇怪的语法(来自维基百科):
register short *to, *from;
register int count;
{
register int n = (count + 7) / 8;
switch(count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while(--n > 0);
}
}
Run Code Online (Sandbox Code Playgroud)
我正在阅读switch语句的C++标准定义(如果过时,请告诉我,我不熟悉Open-Std.org).据我所知,case语句只是简化的switch语句,供switch语句使用.
开关本身完全忽略嵌套的do-while,循环忽略case语句.由于开关在循环内部跳转,因此执行循环.开关用于覆盖剩余部分(从8除以),循环处理可被整除的部分.这一切都有道理.
我的问题是为什么笨拙的语法?在我看来,可以编写循环使得所有case语句都包含在其中,是吗?我在标准中没有看到禁止此行为的任何内容,并且它在GCC 4.7下正确编译,以下被认为是合法的吗?
register short …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用Android jobb工具为我的应用程序创建一个大型OBB文件,但我受到"FAT Full"IOException的困扰:
java.io.IOException: FAT Full (XXXX, YYYY)
at de.waldheinz.fs.fat.Fat.allocNew(Fat.java:298)
at de.waldheinz.fs.fat.Fat.allocAppend(Fat.java:376)
at de.waldheinz.fs.fat.ClusterChain.setChainLength(ClusterChain.java:175)
at de.waldheinz.fs.fat.ClusterChain.setSize(ClusterChain.java:132)
at de.waldheinz.fs.fat.FatFile.setLength(FatFile.java:91)
at de.waldheinz.fs.fat.FatFile.write(FatFile.java:154)
at com.android.jobb.Main$1.processFile(Main.java:495)
at com.android.jobb.Main.processAllFiles(Main.java:604)
at com.android.jobb.Main.processAllFiles(Main.java:600)
at com.android.jobb.Main.main(Main.java:417)
Exception in thread "main" java.lang.RuntimeException: Error getting/writing file with name: LAST_PROCESSED_FILE
at com.android.jobb.Main$1.processFile(Main.java:501)
at com.android.jobb.Main.processAllFiles(Main.java:604)
at com.android.jobb.Main.processAllFiles(Main.java:600)
at com.android.jobb.Main.main(Main.java:417)
Run Code Online (Sandbox Code Playgroud)
在上面的错误消息中,XXXX总是打印为一个低于YYYY的整数值,并且代表可用"簇"的数量(我对存储术语的了解不足以确切知道这意味着什么).YYYY代表最后一个成功分配的集群索引,根据我的经验,它始终与最后一个可用的集群索引相同(数组的大小为XXXX + 2,因此XXXX + 1与YYYY相同是最后一个可用的索引).
崩溃似乎出现在总文件大小超过511 MB的位置(实际限制为536,193,820字节,单个字节更多导致溢出!),因此LAST_PROCESSED_FILE相当任意,但它列出了正在处理的文件发生了崩溃.鉴于存储格式是FAT16(据我所知),那么最大文件大小不应该是2 GB吗?
我已经通过各种来源阅读了空的或小的目录或文件,小的总文件大小或超过500 MB的目录中的单个文件可能导致此崩溃(尽管我无法确定原因).这些原因都不适用于我的情况(这也是基于总文件大小).
我自己对jobb工具源的评论没有提供任何见解.任何人都可以请棚任何光线在这个问题上?
试图设计一些无异常的类,我有一个类似于此的继承结构,但是我发现noexcept说明符在使用成员函数时几乎没有帮助,因为说明符没有作为函数内的范围.
class Base
{
protected:
Base() noexcept {}
};
class Derived : public Base
{
public:
// error: 'Base::Base()' is protected
Derived() noexcept(noexcept(Base{})) : Base{} {}
// error: 'foo' was not declared in this scope
Derived(int) noexcept(noexcept(foo())) {}
// error: invalid use of 'this' at top level
Derived(float) noexcept(noexcept(this->foo())) {}
void foo() noexcept {}
};
Run Code Online (Sandbox Code Playgroud)
这可能是C++ 17中正在改进的东西吗?试图搜索这个没有产生相关结果.现在我已经辞职了一些非常丑陋(可能是不正确的)尝试noexcept(noexcept(static_cast<Derived*>(nullptr)->foo())),但这对基类构造函数的情况没有帮助,它受到保护.
目前是否可以声明一个引用受保护的基类方法的noexcept说明符?noexcept(auto) 可能是相关的,但当然不可能.我是否忽略了允许我包含此说明符的任何其他内容,或者在这种情况下我是否只需忽略它?
c++ ×6
c++11 ×4
c++17 ×2
constexpr ×2
android ×1
duffs-device ×1
ioexception ×1
noexcept ×1
nullptr ×1
shared-ptr ×1
std ×1
stl ×1
templates ×1