您如何将一个相当大(> 300K),相当成熟的C代码库转换为C++?
CI的类型被分为大致对应于模块的文件(即,比典型的基于OO类的分解更少的粒度),使用内部链接代替私有函数和数据,以及公共函数和数据的外部链接.全局变量广泛用于模块之间的通信.有一个非常广泛的集成测试套件,但没有单元(即模块)级别测试.
我想到了一个总体战略:
显然,这将是相当多的工作.关于这种翻译,是否有任何案例研究/战争故事?替代策略?其他有用的建议?
注1:程序是一个编译器,可能数以百万计的其他程序依赖于它的行为不会改变,所以批量重写几乎不是一个选择.
注2:来源近20年,每年可能有30%的代码流失(线路修改+增加/以前的总线路).换句话说,它被大量维护和扩展.因此,其中一个目标是增加可持续性.
[为了这个问题,假设转换为C++是强制性的,而将它留在C中则不是一种选择.添加这个条件的重点是清除"留在C中"的答案.]
在给定任意种子值的情况下,是否有任何已知的算法可以在线性时间和常数空间(当迭代生成输出时)生成混洗范围[0..n]?
假设n可能很大,例如数百万,因此不需要潜在地产生每种可能的排列,尤其是因为它是不可行的(种子值空间需要很大).这也是需要恒定空间的原因.(所以,我特别不是在寻找一种阵列混洗算法,因为这需要将范围存储在长度为n的数组中,因此会使用线性空间.)
我知道问题162606,但它没有给出这个特定问题的答案 - 从排列索引到该问题中给出的排列的映射需要巨大的种子值空间.
理想情况下,它的行为类似于具有周期和范围的LCGn,但选择a和c制作LCG 的艺术是微妙的.只要满足约束a,并c在一个完整周期LCG可满足我的要求,但如果有更好的想法在那里我想知道.
我正在使用MySQL 5.5.我注意到在并发场景中发生了一个特殊的死锁,我不认为应该发生这种死锁.
使用两个同时运行的mysql客户端会话重现:
mysql会话1:
create table parent (id int(11) primary key);
insert into parent values (1);
create table child (id int(11) primary key, parent_id int(11), foreign key (parent_id) references parent(id));
begin;
insert into child (id, parent_id) values (10, 1);
-- this will create shared lock on parent(1)
Run Code Online (Sandbox Code Playgroud)
mysql session 2:
begin;
-- try and get exclusive lock on parent row
select id from parent where id = 1 for update;
-- this will block because of shared lock …Run Code Online (Sandbox Code Playgroud) 我有一个问题:我需要根据文件路径前缀节省空间的文件系统数据查找.换句话说,前缀搜索已排序的文本.你说,使用trie,我也想到了同样的事情.麻烦的是,尝试不够节省空间,没有其他技巧.
我有相当数量的数据:
我不想在内存中接近450M的任何地方吃东西.在这一点上,我很乐意在大约100M左右使用,因为前缀形式有很多冗余.
我正在使用C#来完成这项工作,并且直接实现trie仍然需要为文件中的每一行提供一个叶子节点.假定每个叶子节点都需要对最后一个文本块进行某种引用(32位,比如指向一个字符串数据数组的索引以最小化字符串重复),并且CLR对象开销是8个字节(使用windbg/SOS验证) ,我将花费> 96,000,000字节的结构开销,根本没有文本存储.
让我们看一下数据的一些统计属性.当塞进一个特里:
叶片产生的过剩率约为15%,多余的内部节点产生率为22% - 过量创建,我的意思是在构造期间创建的叶子和内部节点,但不是在最终的trie中,作为每种类型的最终节点数的一部分.
这是来自SOS的堆分析,指示使用最多内存的位置:
[MT ]--[Count]----[ Size]-[Class ]
03563150 11 1584 System.Collections.Hashtable+bucket[]
03561630 24 4636 System.Char[]
03563470 8 6000 System.Byte[]
00193558 425 74788 Free
00984ac8 14457 462624 MiniList`1+<GetEnumerator>d__0[[StringTrie+Node]]
03562b9c 6 11573372 System.Int32[]
*009835a0 1456066 23297056 StringTrie+InteriorNode
035576dc 1 46292000 Dictionary`2+Entry[[String],[Int32]][]
*035341d0 1456085 69730164 System.Object[]
*03560a00 1747257 80435032 System.String
*00983a54 8052746 96632952 StringTrie+LeafNode
Run Code Online (Sandbox Code Playgroud)
将Dictionary<string,int>被用于映射串块到索引到List<string>,并能特里施工后丢弃,虽然GC似乎并没有被删除它(一对夫妇明确集合了这个转储前完成) - !gcroot在SOS并不表示任何根,但我预计后来的GC会释放它.
MiniList<T> …
在C和C++中,变量可以标记为volatile,这意味着编译器不会对其进行优化,因为它可以在声明对象外部进行修改.在Delphi编程中是否有相同的东西?如果不是关键字,也许可以解决?
我的想法是使用绝对,但我不确定,这可能会引入其他副作用.
当应用程序将其输出通过管道传送到另一个程序时,.NET Console类及其默认TextWriter实现(Console.Out在例如,可以隐含地显示Console.WriteLine())不会发出任何错误信号,而另一个程序在应用程序完成之前终止或关闭管道.这意味着应用程序可能会运行超过必要的时间,将输出写入黑洞.
如何检测重定向管道另一端的关闭?
更详细的解释如下:
以下是一对演示此问题的示例程序.Produce很慢地打印很多整数,以模拟计算的效果:
using System;
class Produce
{
static void Main()
{
for (int i = 0; i < 10000; ++i)
{
System.Threading.Thread.Sleep(100); // added for effect
Console.WriteLine(i);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Consume 只读取前10行输入然后退出:
using System;
class Consume
{
static void Main()
{
for (int i = 0; i < 10; ++i)
Console.ReadLine();
}
}
Run Code Online (Sandbox Code Playgroud)
如果编译了这两个程序,并将第一个管道输出到第二个,就像这样:
Produce | Consume
Run Code Online (Sandbox Code Playgroud)
...可以观察到,Produce在Consume终止后长时间保持运行.
实际上,我的Consume程序是Unix风格的head,我的Produce …
在Delphi中编写网络代码的正常方式是使用Windows风格的重叠异步套接字I/O?
这是我之前对这个问题的研究:
在印地部件似乎完全同步.另一方面,虽然ScktComp单元确实使用WSAAsyncSelect,但它基本上只与BSD样式的多路复用套接字应用程序异步.您将被转储到单个事件回调中,就像您刚从循环中的select()返回一样,并且必须自己完成所有状态机导航.
使用Socket.BeginRead/Socket.EndRead,.NET的情况要好得多,其中延续会直接传递给Socket.BeginRead,这就是你选择备份的地方.编码为闭包的延续显然具有您需要的所有上下文等等.
在我的程序中,我有一个25个双值的数组0.04当我尝试在循环中求和这些值时,得到以下结果:
0.0 + 0.04 = 0.04
0.04 + 0.04 = 0.08
0.08 + 0.04 = 0.12
0.12 + 0.04 = 0.16
0.16 + 0.04 = 0.2
0.2 + 0.04 = 0.24000000000000002
0.24000000000000002 + 0.04 = 0.28
0.28 + 0.04 = 0.32
0.32 + 0.04 = 0.36
0.36 + 0.04 = 0.39999999999999997
0.39999999999999997 + 0.04 = 0.43999999999999995
0.43999999999999995 + 0.04 = 0.4799999999999999
0.4799999999999999 + 0.04 = 0.5199999999999999
0.5199999999999999 + 0.04 = 0.5599999999999999
0.5599999999999999 + 0.04 = 0.6
0.6 + 0.04 = …Run Code Online (Sandbox Code Playgroud) 在过去,我使用gcc的C99风格的 C++ 复合文字扩展来编码代码中的嵌套常量数据结构.这是一个例子:
#include <iostream>
using namespace std;
struct Tree {
const char *name;
const Tree *left;
const Tree *right;
};
const Tree *const tree = (Tree []) {
"top", // name
(Tree[]) {
"left",
0,
0
},
(Tree[]) {
"right",
0,
0
}
};
static void dump(const Tree *tree) {
if (!tree) {
cout << "null";
return;
}
cout << tree->name << "(";
dump(tree->left);
cout << ", ";
dump(tree->right);
cout << ")";
}
int main(void) {
dump(tree); …Run Code Online (Sandbox Code Playgroud) .NET有一个名为的函数GC.KeepAlive(Object).其唯一目的是确保引用对象的生命周期持续到代码流到达调用.
除非有人与本机代码进行互操作,否则通常不需要这样做.
我有一种情况,我有一个通过JNI访问的C++对象的图形,其中某些根对象需要保持活动以保持孩子们活着.根对象和子对象都在JVM域中具有镜像.但是,如果在C++端(通过SWIG生成的终结器)收集和释放根对象,则子对象将变为无效,因为它们的C++后备对象将被释放.
这可以通过确保根对象图的局部变量的生命周期超过上次使用子对象来解决.所以我需要一个惯用的函数,它不会对对象做任何事情,但不会被优化掉或移动(例如从循环中提升).这就是GC.KeepAlive(Object).NET中的功能.
Java中的近似等价物是什么?
PS:一些可能的说明性代码:
class Parent {
long ptr;
void finalize() { free(ptr); }
Child getChild() { return new Child(expensive_operation(ptr)); }
}
class Child {
long ptr;
void doStuff() { do_stuff(ptr); }
}
// BAD CODE with potential for SIGSEGV
for (Parent p : getParents()) {
p.getChild().doStuff();
}
Run Code Online (Sandbox Code Playgroud)
麻烦的是,在doStuff执行时,GC释放Parent p将释放为Child分配的内存.已经观察到GC在实践中这样做.GC.KeepAlive可用的潜在修复:
// BAD CODE with potential for SIGSEGV
for (Parent p : getParents()) {
p.getChild().doStuff();
GC.KeepAlive(p);
}
Run Code Online (Sandbox Code Playgroud)
我可以例如调用toStringp,但我不会对其输出做任何事情.我可以暂时将p戳到一个数组中,但我怎么知道JVM不会丢弃商店?等等.
.net java java-native-interface garbage-collection finalizer
.net ×3
algorithm ×2
c ×2
c# ×2
c++ ×2
delphi ×2
java ×2
asynchronous ×1
c++11 ×1
clang ×1
deadlock ×1
finalizer ×1
g++ ×1
legacy ×1
math ×1
memory-model ×1
mysql ×1
networking ×1
pipe ×1
prefix ×1
random ×1
redirect ×1
refactoring ×1
shuffle ×1
sockets ×1
sql ×1
stream ×1
trie ×1
volatile ×1
winapi ×1