考虑以下代码:
int main() {
int *i = nullptr;
delete i;
}
Run Code Online (Sandbox Code Playgroud)
问题:
阅读David Bacon的垃圾收集统一理论 我发现他提到现代GC是追踪和参考计数的混合物:
鉴于我们在跟踪和引用计数之间发现的结构相似性,我们开始重新检查各种收集器体系结构,以了解这些样式的集合之间的相互作用.我们观察到所有真实的垃圾收集器实际上是跟踪和引用计数的某种形式的混合.这就解释了为什么优化的"跟踪收集器"和优化的"引用计数收集器"变得越来越相似:因为它们实际上具有彼此的特性.
他提到的一件事是使用ZCT(零计数表)来跟踪从堆栈引用的对象.关于ARC的另一件事是:
我的问题:现代C++(11/14/17)与这些陈述相比如何?这是真的,C++的ARC是混合的,也使用跟踪GC的一些元素?我在网上找不到任何指向我的内容,但该文件非常明确地指出:
我们观察到所有真实的垃圾收集器实际上是跟踪和引用计数的某种形式的混合.
这是关于现代C++的吗?或者它不认为C++ ARC是一个"真实的垃圾收集器"?有些人可能认为C++没有GC,C++没有跟踪GC,但ARC是一种GC方法,正如它在论文中所述:
跟踪和引用计数统一被视为具有非常独特的性能属性的垃圾收集的根本不同的方法.我们已经实现了两种类型的高性能收集器,并且在此过程中观察到我们对它们的优化越多,它们表现得越相似 - 它们似乎共享一些深层结构.
引用计数是一种垃圾收集形式,每个对象都有一个对它的引用数量的计数.通过引用计数为零来识别垃圾.对象的引用计数在创建对它的引用时递增,在引用被销毁时递减.当计数达到零时,将回收对象的内存.
此外,还有针对GC分配/释放的现代C++ ARC的任何基准(注意:我不是要求进行一般比较,而是要求内存管理).
最后但并非最不重要的,如果我正在开发一个单线程应用程序,那么在C++上使用递增/递减作为原子操作的优势是什么?无论如何要禁用它?
这是我的完整代码:
#include <iostream>
#include <vector>
#include <bits/stdc++.h>
using namespace std;
#define ff first
#define mp make_pair
#define ss second
int main(void) {
int m;
vector <string> grid;
cin >> m;
pair <int,int> foo;
pair <int,int> bar;
// bar =make_pair (10.5,'A');
foo = make_pair (1,2);
cout<<foo.ss<<endl;
for(int i=0; i<m; i++) {
string s; cin >> s;
grid.push_back(s);
int pp = s.find('p');
int mp = s.find('m');
if(pp>=0){
bar = make_pair(pp,i);
}
cout<<pp<<endl;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是我的错误:
prog.cpp: In function 'int main()': …Run Code Online (Sandbox Code Playgroud) 我有一个隐藏默认构造函数的类,强制使用带参数的构造函数.另一个类使用该类的2个实例:
typedef struct { ... } BAZ;
class Foo {
private:
Foo(void) {}
public:
Foo(BAZ a) { ... }
};
class Bar {
private:
Foo foo1;
Foo foo2;
Bar(void) {}
public:
Bar(BAZ a, BAZ b) : foo1(a), foo2(b) { ... }
};
Run Code Online (Sandbox Code Playgroud)
最明显的是变量foo1和foo2的声明将调用默认的Foo构造函数,但由于它是私有的,它不能并且会给编译器错误.
有没有办法阻止它尝试默认的Foo构造函数,只是等待Bar构造函数初始化它们?
我想避免使用new关键字(这将解决整个问题).
编辑:
似乎人们很难理解问题和困境.我会试着解释一下:
我想强制使用Foo(BAZ)构造函数,这意味着任何使用Foo(void)构造函数的尝试都会产生错误.
要隐藏默认构造函数,它将被声明为私有成员.如果有人试图使用默认构造函数Foo(),它将给出故意错误.
要不声明默认构造函数,只声明Foo(BAZ)不会阻止编译器创建公共默认构造函数.如果我将其声明为Foo(),则不会出错.到目前为止它的工作正常并且符合预期.
第二类Bar有两个Foo实例,但是当实例化Bar时,这些Foo成员将使用默认(隐藏)构造函数调用并生成错误.然后在Bar构造函数中,这两个实例将使用正确的公共构造函数Bar(BAZ a,BAZ b)初始化:foo1(a),foo2(b).这就是我要的.
有没有办法防止它在初始化Bar时调用Foo默认构造函数,所以Bar构造函数可以使用正确的Foo构造函数?
该新解决方案的工作,因为默认的构造函数永远不会被调用:
BAZ a = {...}
Foo *foo1 = new Foo(a);
Run Code Online (Sandbox Code Playgroud)
我希望这更清楚.
EDIT2:已解决 错误不在隐藏的Foo构造函数中,它是隐藏的Bar构造函数,试图使用隐藏的默认Foo构造函数.
Bar(void) : Foo(BAZ{}), Foo(BAZ{}) {}
Run Code Online (Sandbox Code Playgroud)
解决了它.
编辑3:
真正的问题似乎是在开发工具中.重新启动并手动清除缓存后,它就像C++ 14标准一样工作.
我正在寻找更详细的答案,而不是UB是UB.
我有一段遗留代码,我知道是异常的罪魁祸首.我们以前memset一个向量,一旦它被更改为unordered_map,它就会在销毁时抛出异常.在源代码中,memsetting一个向量与unordered_map有什么不同?它们都与连续的记忆相互作用......
在我们的代码中,我们有这个.(我为伪代码道歉,但重点应该是可以理解的......)
class B
{
std::vector<CustomObject> vect;
};
struct STRUCT_A
{
B b;
};
Run Code Online (Sandbox Code Playgroud)
后来我们这样做......
STRUCT_A m_struct_a;
memset(&m_struct_a, 0, sizeof(STRUCT_A));
Run Code Online (Sandbox Code Playgroud)
即使我们memset一个stl :: container,这个工作也很好!但是,如果我们将类B更改为具有映射,则析构函数上会发生异常.
class B
{
std::map<CustomObject> vect;
};
Run Code Online (Sandbox Code Playgroud)
所以我认为它与矢量是连续的有关,所以我把它改成了unordered_map
class B
{
std::unordered_map<CustomObject> vect;
};
Run Code Online (Sandbox Code Playgroud)
析构函数仍然会抛出异常.我觉得这很有趣,并认为这是一个很好的问题......
当我在Linux,Windows和在线编译器上运行这些源代码时,它总是提供不同的结果,但我认为两个源代码都是相同的.请描述有关这些代码的任何想法.
第一个代码:
#include<iostream>
using namespace std;
int main()
{
double a=100.0,b=50.0,c=0.0,da,db,dc;
double k1=0.008,k2=0.002,delta=0.1,T=5.0,t,time=0.0;
int N;
t=(T/delta);
N=(int)t;
cout<<"Time"<<"\t"<<"A"<<"\t"<<"B"<<"\t"<<"C"<<"\t\n";
cout<<time<<"\t"<<a<<"\t"<<b<<"\t"<<c<<"\t\n";
for(int i=0;i<N;i++)
{
//Look the below line
a=a+(k2*c-k1*a*b)*delta;
b=b+(k2*c-k1*a*b)*delta;
c=c+(2*(k1*a*b-k2*c))*delta;
time+=delta;
cout<<time<<"\t"<<a<<"\t"<<b<<"\t"<<c<<"\t\n";
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
第二代码:
#include<iostream>
using namespace std;
int main()
{
double a=100.0,b=50.0,c=0.0,da,db,dc;
double k1=0.008,k2=0.002,delta=0.1,T=5.0,t,time=0.0;
int N;
t=(T/delta);
N=(int)t;
cout<<"Time"<<"\t"<<"A"<<"\t"<<"B"<<"\t"<<"C"<<"\t\n";
cout<<time<<"\t"<<a<<"\t"<<b<<"\t"<<c<<"\t\n";
for(int i=0;i<N;i++)
{
//Separate the previous code into two line.
da=k2*c-k1*a*b;
db=k2*c-k1*a*b;
dc=2*(k1*a*b-k2*c);
a=a+da*delta;
b=b+db*delta;
c=c+dc*delta;
time+=delta;
cout<<time<<"\t"<<a<<"\t"<<b<<"\t"<<c<<"\t\n";
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:第一次迭代后:
first code gives : …Run Code Online (Sandbox Code Playgroud) 我正在编写与 C/C++ 中的引用相关的代码。我创建了一个指针并将其放入一个递增它的函数中。在函数中,我编写*ptr++并尝试增加指针指向的整数的值。
#include <iostream>
using namespace std;
void increment(int *ptr)
{
int &ref = *ptr;
*ptr++; // gets ignored?
ref++;
}
int main()
{
int a = 5;
increment(&a);
cout << a;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
谁能告诉我为什么我不能增加变量?我尝试使用 来增加它+=1,它可以工作,但不能通过使用++运算符?
如果字符串是科学格式,我想将一个给定的字符串转换为double而不将该值转换为十进制.
即1.23e1应保存为1.23e1而不是12.3.
我检查了stringstream,strtod,boost :: lexical_cast等方法,但所有这些方法都将1.23e1转换为12.3.
有没有办法使1.23e1可以保存为1.23e1而不是12.3 ??
我正在测试下面的代码,但编译器在我用C++ 11编译时说:
error: call of overloaded ‘func_A(int)’ is ambiguous
谁能解释一下?
这是代码:
template<typename T> class MC {
public:
void func_A(int a, T initvalue = T()) {}
void func_A(int a) {}
void func_B(int b, T) {}
void func_B(int b) {}
};
int main(void) {
MC<int> mc;
mc.func_A(1); // error: detects call of overloaded
mc.func_A(1,2); // OK
mc.func_B(10); // OK
mc.func_B(10,11); // OK
return 0;
}
Run Code Online (Sandbox Code Playgroud)
完整的编译消息:
$ g++ -std=c++11 test.cpp
test.cpp: In function ‘int main()’:
test.cpp:12:16: error: call of overloaded ‘func_A(int)’ is …Run Code Online (Sandbox Code Playgroud) 我尝试使用10 ^ 6乘10 ^ 6阵列,它给我分段故障
int main () {
std::vector <int> elements;
elements.push_back (1);
elements [10000] = 102;
std:: cout << elements [10000];
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码如何工作?据我所知,矢量的增长率为1.5 - 2倍.那么第10000个元素如何存储在这里?这里的预期行为不是"分段错误"吗?但以上运行成功.
string s="1 23";
string a;
a[0]=s[2];a[1]=s[3];
cout<<a;
Run Code Online (Sandbox Code Playgroud)
在这里,我无法获得输出字符串 a。但是我可以通过 a[0] 获取所有单个元素。
这是需要优化的代码
#include <iostream>
using namespace std;
int main() {
// size of cross, use odd number
int size = 5;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (i==j || i+j==size-1) {
cout << "*";
} else {
cout << " ";
}
}
cout << "\n";
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出
* *
* *
*
* *
* *
Run Code Online (Sandbox Code Playgroud)
请让我知道任何来源或参考文献(如果有)...
c++ ×13
c++14 ×13
c++11 ×4
atmelstudio ×1
constructor ×1
increment ×1
null-pointer ×1
optimization ×1
std-pair ×1
stdvector ×1