小编Bar*_*lly的帖子

将C源转换为C++

您如何将一个相当大(> 300K),相当成熟的C代码库转换为C++?

CI的类型被分为大致对应于模块的文件(即,比典型的基于OO类的分解更少的粒度),使用内部链接代替私有函数和数据,以及公共函数和数据的外部链接.全局变量广泛用于模块之间的通信.有一个非常广泛的集成测试套件,但没有单元(即模块)级别测试.

我想到了一个总体战略:

  1. 在C++的C子集中编译所有内容并使其正常工作.
  2. 将模块转换为大型类,以便所有交叉引用都由类名限定,但将所有函数和数据保留为静态成员,并使其工作.
  3. 使用适当的构造函数和初始化的交叉引用将巨大的类转换为实例; 根据需要使用间接访问替换静态成员访问; 让它工作.
  4. 现在,将项目作为一个错误的OO应用程序来处理,并编写单元测试,其中依赖项是易处理的,并分解为不属于它们的单独类; 这里的目标是在每次转型时从一个工作计划转移到另一个工作计划.

显然,这将是相当多的工作.关于这种翻译,是否有任何案例研究/战争故事?替代策略?其他有用的建议?

注1:程序是一个编译器,可能数以百万计的其他程序依赖于它的行为不会改变,所以批量重写几乎不是一个选择.

注2:来源近20年,每年可能有30%的代码流失(线路修改+增加/以前的总线路).换句话说,它被大量维护和扩展.因此,其中一个目标是增加可持续性.

[为了这个问题,假设转换为C++是强制性的,而将它留在C中则不是一种选择.添加这个条件的重点是清除"留在C中"的答案.]

c c++ legacy refactoring program-transformation

41
推荐指数
4
解决办法
3万
查看次数

使用PRNG而不是改组来生成随机范围

在给定任意种子值的情况下,是否有任何已知的算法可以在线性时间和常数空间(当迭代生成输出时)生成混洗范围[0..n]?

假设n可能很大,例如数百万,因此不需要潜在地产生每种可能的排列,尤其是因为它是不可行的(种子值空间需要很大).这也是需要恒定空间的原因.(所以,我特别不是在寻找一种阵列混洗算法,因为这需要将范围存储在长度为n的数组中,因此会使用线性空间.)

我知道问题162606,但它没有给出这个特定问题的答案 - 从排列索引到该问题中给出的排列的映射需要巨大的种子值空间.

理想情况下,它的行为类似于具有周期和范围的LCGn,但选择ac制作LCG 的艺术是微妙的.只要满足约束a,并c在一个完整周期LCG可满足我的要求,但如果有更好的想法在那里我想知道.

language-agnostic random algorithm shuffle

23
推荐指数
3
解决办法
2148
查看次数

将共享升级到独占锁时避免MySQL死锁

我正在使用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)

mysql sql deadlock

22
推荐指数
1
解决办法
1820
查看次数

节省空间的内存结构,用于支持前缀搜索的排序文本

我有一个问题:我需要根据文件路径前缀节省空间的文件系统数据查找.换句话说,前缀搜索已排序的文本.你说,使用trie,我也想到了同样的事情.麻烦的是,尝试不够节省空间,没有其他技巧.

我有相当数量的数据:

  • 在磁盘上以纯文本Unix格式列出大约450M
  • 大约800万行
  • gzip默认压缩到31M
  • bzip2默认压缩到21M

我不想在内存中接近450M的任何地方吃东西.在这一点上,我很乐意在大约100M左右使用,因为前缀形式有很多冗余.

我正在使用C#来完成这项工作,并且直接实现trie仍然需要为文件中的每一行提供一个叶子节点.假定每个叶子节点都需要对最后一个文本块进行某种引用(32位,比如指向一个字符串数据数组的索引以最小化字符串重复),并且CLR对象开销是8个字节(使用windbg/SOS验证) ,我将花费> 96,000,000字节的结构开销,根本没有文本存储.

让我们看一下数据的一些统计属性.当塞进一个特里:

  • 文字总数独特的"块"约110万
  • 文本文件中磁盘上大约16M的唯一块总数
  • 平均块长度为5.5个字符,最大值为136
  • 当没有考虑重复时,总共大约5200万个字符
  • 内部trie节点平均约6.5个孩子,最多44个
  • 约1.8M内部节点.

叶片产生的过剩率约为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> …

.net c# algorithm prefix trie

14
推荐指数
1
解决办法
1961
查看次数

Delphi是否有任何与C的volatile变量等价的东西?

在C和C++中,变量可以标记为volatile,这意味着编译器不会对其进行优化,因为它可以在声明对象外部进行修改.在Delphi编程中是否有相同的东西?如果不是关键字,也许可以解决?

我的想法是使用绝对,但我不确定,这可能会引入其他副作用.

c delphi multithreading volatile memory-model

13
推荐指数
2
解决办法
3780
查看次数

在.NET应用程序中检测重定向控制台输出中的已关闭管道

当应用程序将其输出通过管道传送到另一个程序时,.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)

...可以观察到,ProduceConsume终止后长时间保持运行.

实际上,我的Consume程序是Unix风格的head,我的Produce …

.net c# redirect pipe stream

11
推荐指数
1
解决办法
2048
查看次数

在Delphi中进行异步套接字编程的惯用方法是什么?

在Delphi中编写网络代码的正常方式是使用Windows风格的重叠异步套接字I/O?

这是我之前对这个问题的研究:

印地部件似乎完全同步.另一方面,虽然ScktComp单元确实使用WSAAsyncSelect,但它基本上只与BSD样式的多路复用套接字应用程序异步.您将被转储到单个事件回调中,就像您刚从循环中的select()返回一样,并且必须自己完成所有状态机导航.

使用Socket.BeginRead/Socket.EndRead,.NET的情况要好得多,其中延续会直接传递给Socket.BeginRead,这就是你选择备份的地方.编码为闭包的延续显然具有您需要的所有上下文等等.

sockets delphi networking winapi asynchronous

10
推荐指数
1
解决办法
5792
查看次数

Java程序中奇怪的浮点行为

在我的程序中,我有一个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)

java math

10
推荐指数
3
解决办法
2558
查看次数

如何在C++中编码大型复杂,常量的数据结构

在过去,我使用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)

c++ g++ clang c++11

9
推荐指数
1
解决办法
1509
查看次数

什么是.net的GC.KeepAlive的Java等价物?

.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

9
推荐指数
1
解决办法
471
查看次数