我知道很少有C++常见问题解答(以及SO上的答案)说没有必要检查普通new-expression的返回值为null,因为普通的new-expression通过抛出异常来表示失败.他们基本上声明普通的new-expression永远不会返回null.(通过"普通新表达式"我的意思是一个不是一个新表达式nothrow).
然而,尽管这看起来像一个非常基本的问题,我突然意识到,当他们给出答案时,我不明白他们做出的具体假设(如果有的话).
特别是,我想知道我是否允许重载基本的普通形式::operator new以始终返回空指针,因此期望所有使用该运算符的普通新表达式现在也将返回空指针.
根据语言规范,如果我::operator new被声明为非投掷,那么我可能/将通过返回空指针来指示内存分配失败.所以,让我们这样做
void *operator new(size_t s) throw() {
return 0;
}
int main() {
int *i = new int;
}
Run Code Online (Sandbox Code Playgroud)
在我的实验中,上面的new-expression确实成功返回一个空指针.那么,我是否违反了上述代码中的任何规则?宣布平原::operator new为非投掷是否合法?
如果上面的代码没问题,那么我认为当有人声明一个普通的新"永不返回空指针"时,他们会假设标准库提供的版本::operator new没有被替换.这个推定是否正确?
C++语言标准在D.5中说
2每个C标头(每个标头都有一个表单名称)的
name.h行为就好像每个由相应cname标头放置在标准库名称空间中的名称放在全局名称空间范围内.未指定是否首先在命名空间的命名空间范围(3.3.6)中声明或定义这些名称std,然后通过显式using-declarations(7.3.3)将这些名称注入到全局命名空间范围中.3 [示例:标头
<cstdlib>确实在命名空间中提供其声明和定义std.它还可以在全局命名空间中提供这些名称.标题<stdlib.h>肯定在全局命名空间中提供相同的声明和定义,就像在C标准中一样.它还可以在命名空间中提供这些名称std. - 末端的例子]
这似乎相当明确地说明了("......每个名字......","......相同的声明......")旧式<name.h>标题必须提供与新式标题相同的声明<cname>集,但在全局命名空间.例如,对于各种C函数的C++特定重载版本,没有例外.
这似乎意味着,<math.h>必须提供三个版本的sin功能:sin(float),sin(double)并sin(long double)在全局命名空间.反过来,这意味着以下C++代码应该无法解决重载问题
#include <math.h>
int main() {
sin(1);
}
Run Code Online (Sandbox Code Playgroud)
它在MSVC++编译器下失败,但它在GCC和Clang下成功编译.那么,GCC是否只是忽略了已弃用的旧式标题的标准要求?还是我以某种方式误解了标准中的措辞?
这种特殊的nextafter(和nexttoward)函数接口背后的原因究竟是什么?我们指定的方向通过指定我们想要移动的价值走向。
乍一看,这个想法背后似乎隐藏着一些不明显的东西。在我(天真)看来,此类函数的首选将类似于一对单参数函数nextafter(a)/ nextbefore(a)。下一个选择将是一个双参数函数nextafter(a, dir),其中dir明确指定方向(-1和+1,一些标准枚举等)。
而是我们必须指定一个值,我们希望移动走向。因此有许多问题
(一个模糊的)。可能有一些聪明的想法或惯用的模式非常有价值,以至于影响了这些标准功能中的接口选择。在那儿?
如果决定盲目地使用-DBL_MAX和+DBL_MAX作为nextafter分别指定负方向和正方向的第二个参数会怎样。这样做有什么陷阱吗?
(2 的改进)。如果我知道肯定b是[轻微]大于a,没有任何理由,更喜欢nextafter(a, b)了nextafter(a, DBL_MAX)?例如,nextafter(a, b)版本是否有更好的性能?
是nextafter通常一个沉重的操作?我知道它是依赖于实现的。但是,再次假设一个基于 IEEE 754 表示的实现,找到相邻的浮点值是否相当“困难”?
请考虑以下示例
template <typename A> struct S
{
A a;
void foo() {}
};
template <typename T> void bar()
{
S<void> *p = 0;
}
template <typename T> void baz()
{
S<void>{}.foo();
}
template <typename T> void qux()
{
S<void> s{};
}
int main()
{
}
Run Code Online (Sandbox Code Playgroud)
功能模板bar,baz并qux故意留下非实例化.
由于baz"明显"的原因,未能在GCC和Clang中编译的定义S<void>是无效的专业化S.但是,在这种情况下,哪种语言规则正在起作用?
一方面,S<void>不依赖于模板参数baz,成员访问要求它完成,从而触发实例化S<void>,失败.诊断是必需的.
另一方面,我们有一条全面的规则:"如果没有为非实例化的模板生成有效的专业化,则代码就是格式错误".这使得baz形成不良的定义.但是,不需要诊断.
更具体地说,我是否正确地假设(如#1所述)上述S<void>非实例baz化的引用需要实例化S<void>?两个编译器都乐于接受bar未实例化的定义这一事实支持了这一假设S<void>. …
c++ templates template-specialization language-lawyer template-instantiation
有在C++标准至少两个地方禁止限定对象与不完全类型(http://eel.is/c++draft/basic.def#5,http://eel.is/c++draft/basic .types#5).但是,在C++中通常允许为不完整类型的对象提供非定义声明.而且我似乎无法确定那些禁止void以这种方式声明类型不完整的"对象"的特定部分.(当然,void在一个例子中,它不是C++中的对象类型,但它们都不是引用类型.)所以,就是这样
extern void a;
Run Code Online (Sandbox Code Playgroud)
在C++中真的不合格?
在C void中,允许对象的非定义声明(如上所示),GCC和Clang都接受C代码中的上述内容(当然不允许定义).但在C++代码中,两个编译器都会为此类声明发出错误.标准的哪一部分让他们这样做?
[basic.fundamental]列出了void类型的可能用途(http://eel.is/c++draft/basic.types#basic.fundamental-13),但它似乎并不是一个完整的列表.
以下代码在Clang中编译良好,并输出int [3]数组的大小
#include <iostream>
int main()
{
const int (&a)[] = { 1, 2, 3 };
std::cout << sizeof a << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
但是,在GCC中,该声明可以很好地编译,但sizeof a不能编译:显然,GCC拒绝“推导”数组大小,最终a以引用const int []类型的方式结束,这是不完整的。
这种初始化的预期行为是什么?
在这种情况下,9.3.4 / 3似乎是标准的相关部分,但就其本身而言,似乎并不能得出结论。
当我在GCC和Clang中运行此代码示例时
struct S
{
int a;
void *operator new(size_t s)
{
std::cout << "new " << s << std::endl;
return ::operator new(s);
}
void operator delete(void *p, size_t s) noexcept
{
std::cout << "delete " << s << std::endl;
::operator delete(p);
}
void operator delete(void *p) noexcept
{
std::cout << "delete " << "none" << std::endl;
::operator delete(p);
}
};
int main()
{
S *p = new S;
delete p;
}
Run Code Online (Sandbox Code Playgroud)
我从GCC和Clang得到以下输出
new 4
delete none
Run Code Online (Sandbox Code Playgroud)
这意味着编译器选择的“无尺寸”版本operator delete。 …
c++ operator-overloading language-lawyer delete-operator c++14
这不是跨平台代码......一切都在同一平台上执行(即endianess是相同的..小端).
我有这个代码:
unsigned char array[4] = {'t', 'e', 's', 't'};
unsigned int out = ((array[0]<<24)|(array[1]<<16)|(array[2]<<8)|(array[3]));
std::cout << out << std::endl;
unsigned char buff[4];
memcpy(buff, &out, sizeof(unsigned int));
std::cout << buff << std::endl;
我希望buff的输出是"test"(由于缺少'/ 0'而带有垃圾尾随字符),而输出是"tset".显然改变我正在移动的字符顺序(3,2,1,0而不是0,1,2,3)解决了问题,但我不明白这个问题.memcpy不按我期望的方式行事吗?
谢谢.
当我在VC++ 6中编译以下代码时,我不断收到错误"使用类模板需要模板参数列表".这有什么问题?
template <class T>
class StdVector{
public:
StdVector & operator=(const StdVector &v);
};
template <typename T>
StdVector & StdVector<T>::operator=(const StdVector &v){
return *this;
}
Run Code Online (Sandbox Code Playgroud) 我在理解 ccw(逆时针)算法时遇到了一些麻烦:
int ccw (Point P0, Point P1, Point P2) {
dx1 = P1.x - P0.x;
dx2 = P2.x - P0.x;
dy1 = P1.y - P0.y;
dy2 = P1.y - P0.y;
if (dy1 * dx2 > dy2 * dx1) return -1;
if (dx1 * dy2 > dy1 * dx2) return 1;
if ((dx1 * dx2 < 0) || (dy1 * dy2 < 0)) return 1;
if ((dx1 * dx1 + dy1 * dy1) < (dx2 * dx2 + dy2 * …Run Code Online (Sandbox Code Playgroud)