考虑以下片段:
#include <array>
int main() {
using huge_type = std::array<char, 20*1024*1024>;
huge_type t;
}
Run Code Online (Sandbox Code Playgroud)
显然它会在大多数平台上崩溃,因为默认堆栈大小通常小于 20MB。
现在考虑以下代码:
#include <array>
#include <vector>
int main() {
using huge_type = std::array<char, 20*1024*1024>;
std::vector<huge_type> v(1);
}
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是它也崩溃了!回溯(使用最近的 libstdc++ 版本之一)指向include/bits/stl_uninitialized.h文件,我们可以在其中看到以下几行:
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
std::fill(__first, __last, _ValueType());
Run Code Online (Sandbox Code Playgroud)
调整大小vector构造函数必须默认初始化元素,这就是它的实现方式。显然,_ValueType()临时会导致堆栈崩溃。
问题是它是否是一个符合要求的实现。如果是,那实际上意味着大类型向量的使用非常有限,不是吗?
我目前正在阅读“专家 C 编程 - 深层 C 秘密”,刚刚发现了这个:
\n\n\n\n
auto永远不需要存储类说明符。这对于编译器编写者来说最有意义\n在符号表 \xe2\x80\x94 中创建一个条目,它表示“此存储在进入\n块时自动分配”(而不是在编译时静态分配,或在编译时动态分配)堆)。auto\n对于所有其他程序员来说几乎没有意义,因为它只能在函数内部使用,但是\n函数中的数据声明默认具有此属性。
我看到有人在这里问了同样的事情,但他们没有任何答案,评论中给出的链接仅解释了为什么 C 中有这样一个继承自B 的关键字,以及与 C++ 的差异11 或 C++11 之前版本。
\n无论如何,我发布的内容是为了重点说明auto关键字在编译器编写中以某种方式有用的部分,但是这个想法是什么以及与符号表的联系是什么?
我确实坚持这样一个事实:我只询问用 C 语言编写编译器时的潜在用法(而不是编写 C 编译器)。
\n为了澄清这一点,我问这个问题是因为我想知道是否有一个auto可以证明合理的代码示例,因为作者在编写编译器时表示会有。
这里的重点是我认为已经理解了auto(继承自B,它是强制性的,但在C中无用),但我无法想象使用它时的任何示例是有用的(或者至少不是无用的)。
看起来确实没有任何理由使用auto,但是是否有任何旧的源代码或类似的内容与引用的语句相对应?
我有一个C++类,我只希望它在堆栈上实例化.我正在使用api访问以另一种(解释)语言开发的内容,该语言带有自己的垃圾收集.这种语言中的机制足以将它在堆栈中找到引用的任何内容留下来,并且由于这个本机类包含这样的引用,因此对于正确的行为来说,它本身就是C++类的用户是至关重要的.永远不要尝试在其他任何地方分配它的实例.
注意,我不仅要禁止我的类的实例被分配new(如果这是我需要做的全部,我可以重载类的new运算符并将其设为私有,或者从C++ 11开始明确删除它),但也要禁止该类的任何静态或可能的全局实例.安全地实例化这个类的唯一有效方法应该在堆栈上,我想以某种方式保证.据我所知,new私有或删除它也不会阻止另一个类被我的类声明为成员变量和在堆上分配的实例.
我现在如何处理这个问题就是将"Local"作为类名称的一部分,作为对用户的友好提醒,该实例仅用于堆栈,但当然,这不是'实际上是由编译器或任何其他机制强制执行的,我更喜欢一种更具可执行性的解决方案.
理想情况下,我想在编译时确保这一点,如果使用不正确则编译失败.如果这根本不可能,那么在构造实例时在运行时抛出异常仍然是可接受的回退.在C++ 11或C++ 14中工作的解决方案很好.
请注意,这个问题肯定是不一样的这一个,它只是想防止allocaton与new
与SO上的很多问题和答案相关,我已经了解到最好引用其生命周期被管理为驻留在自动存储而不是堆栈中的对象.
此外,动态分配的对象不应该被称为驻留在堆上,而应该被称为动态存储.
我知道有自动,动态和静态存储,但从来没有真正理解自动堆栈和动态堆之间的区别.为什么前者更受青睐?
我不是在询问堆栈/堆的含义或内存管理的工作原理.我问为什么术语自动/动态存储优于术语堆栈/堆.
就我对资源管理的了解而言,在堆上分配一些东西(操作符new)应该总是比在堆栈上分配(自动存储)慢,因为堆栈是基于LIFO的结构,因此它需要最少的簿记,并且要分配的下一个地址的指针是微不足道的.
到现在为止还挺好.现在看下面的代码:
/* ...includes... */
using std::cout;
using std::cin;
using std::endl;
int bar() { return 42; }
int main()
{
auto s1 = std::chrono::steady_clock::now();
std::packaged_task<int()> pt1(bar);
auto e1 = std::chrono::steady_clock::now();
auto s2 = std::chrono::steady_clock::now();
auto sh_ptr1 = std::make_shared<std::packaged_task<int()> >(bar);
auto e2 = std::chrono::steady_clock::now();
auto first = std::chrono::duration_cast<std::chrono::nanoseconds>(e1-s1);
auto second = std::chrono::duration_cast<std::chrono::nanoseconds>(e2-s2);
cout << "Regular: " << first.count() << endl
<< "Make shared: " << second.count() << endl;
pt1();
(*sh_ptr1)();
cout << "As you can see, both are working …Run Code Online (Sandbox Code Playgroud) 我的产品代码类似于以下内容.据我说,输出是'0 1 2 3'.但类似代码的输出是'1 1 1 1'.
for(i = 0 ;i < 5;i++){
int j;
if(i)
printf("%d ",j);
j = i;
}
Run Code Online (Sandbox Code Playgroud)
我的理解是,在'for'循环的整个周期期间,j仅在堆栈上分配一次,并且在迭代期间使用相同的值.另外,如果我将j的声明移到for循环中,我会得到预期的结果.我在这里错过了什么?
PS - 当我在我的个人计算机上运行相同的代码时,我得到了预期的输出.但在生产方面却有所不同.
其中一些可能是重复的,但我很抱歉.
假设我有这个struct:
struct foo
{
int a;
int b;
int c;
};
Run Code Online (Sandbox Code Playgroud)
1.如果struct foo类型对象以具有自动存储持续时间且没有初始化程序的方式声明,是否可以保证将其所有成员强制初始化为零?
{
// other stuff
struct foo bar;
// other stuff
}
Run Code Online (Sandbox Code Playgroud)
2.如果struct foo类型对象以具有自动存储持续时间的方式声明并且具有一些初始值设定项,是否可以保证未明确初始化的成员将被强制初始化为零?
{
// other stuff
struct foo bar = {.a = 1};
// other stuff
}
Run Code Online (Sandbox Code Playgroud)
3.如果struct foo以具有自动存储持续时间的方式声明类型对象并使用复合文字表达式,是否可以保证未明确初始化的成员将被强制初始化为零?
{
// other stuff
func((struct foo){.a = 1});
// other stuff
}
Run Code Online (Sandbox Code Playgroud)
任何C标准参考都非常感谢!谢谢!
(我的问题的答案涉及复制构造函数,但复制发生在从函数返回时,而不是在对另一个类的方法调用中.我实际上看到引用的可能重复,但没有从vector :: copy制作的副本中推断出来:) push_back我的函数在这里也复制了.也许我应该有.)
我试图了解自动对象的构造/破坏.我遇到了一些看起来很可疑的代码,所以我编写了自己的版本以努力理解它.简而言之,原始代码包含一个返回函数本地对象的函数(自动).这对我来说看起来不安全,所以我写了这个程序来探索它:
#include <stdio.h>
class Phantom
{
private:
static int counter;
int id;
public:
Phantom()
{
++counter;
id = counter;
printf("Phantom %d constructed.\n", id);
};
virtual ~Phantom()
{
printf("Phantom %d destructed.\n", id);
};
void speak()
{
printf("Phantom %d speaks.\n", id);
};
};
int Phantom::counter = 0;
Phantom getPhantom()
{
Phantom autoPhantom;
return autoPhantom; // THIS CAN'T BE SAFE
}
int main()
{
Phantom phantom;
phantom = getPhantom();
phantom.speak();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我得到这个输出:
Phantom 1 constructed. Phantom 2 …
操作系统只会恢复它(在程序退出后)对吗?那么除了良好的编程风格之外还有什么用?还是有什么我误解的?是什么使它与"自动"分配不同,因为两者都可以在运行时更改,并且都在程序执行后结束?
int main()
{
float* ptr;
{
float f{10.f};
ptr = &f;
}
*ptr = 13.f;
// Do more stuff with `*ptr`...
}
Run Code Online (Sandbox Code Playgroud)
它使用/访问有效或未定义的行为*ptr?
我测试了类似于上面示例的情况,并且所有内容似乎都起作用,好像嵌套块中变量的生命周期由于指针而被扩展.
我知道const&(const引用)将延长临时的生命周期.指针是否相同?