posts - 16,  comments - 34,  trackbacks - 0
共10页: First 2 3 4 5 6 7 8 9 10 
@唐风
重复数量有限而且不多时,还是可以接受的……
范型库经常会做这种事情。比如iterator_traits,numeric_limits……

concepts嘛…… 砍了也好……
支持C++标准的谨慎态度。

没有concepts,虽然代码很难写,但也已经写出来了。
但concepts一旦加入标准,又发现它不是想象中那么好的话,就再也拿不掉了。

C++就是拿boost这种库当试验田。
等某个特性确实各方面都符合条件时,再加入标准之中。
而不像java、.net,动不动就加入一个;过段时间发现不好,再加入一个替代品;使得库很臃肿;还要一直保持向下兼容。
C++不是商业公司拥有的…… 没人有这么好的精力做这些事情……

re: XL Library Preview,诚征指点 OwnWaterloo 2009-11-14 19:15
@溪流
哈哈,被你看出来了……
我就是一anti-OOP者……

其实也不是完全是这样。只是太多人将OOP当作万能药了。
以为OOP的设计,就一定是好的设计。OOP成分越多,设计越好。
我反对的是这种态度。

re: XL Library Preview,诚征指点 OwnWaterloo 2009-11-14 15:26
@溪流
我再使用上面的观点狡辩一次吧……

1. 非虚析构
如果、假设、万一真的出现了这样的需求 —— 几乎不可能 —— 需要被继承而且以父类指针delete子类。

还可以这样:
class StringDerivable {
String s_;
public:
virtual ~StringDerivable();
};
并从StringDerivable继承。


2. 虚析构
如果一开始就使用虚析构,无论是否需要被继承 —— 几乎不可能 —— 用户都必须承担一个虚指针的代价。


非虚析构对于不需要继承的客户来说,没有额外的代价。对需要继承的变态客户来说,也有办法实现 —— 多一个步骤。
这是贯穿整个C++语言设计的一个重要原则:0代价原则。
虚析构无论客户是否需要,多态的代价都必须承受。


设计不单单只是你做了什么,也包括你没有做什么。

re: SFINEA in C++ OwnWaterloo 2009-11-14 15:11
代码字体挺好看的。
知名应用抄错了:

enum {value = sizeof(test<T>()) == sizeof(one)};

这里要以一个0去调用test<T>:
enum {value = sizeof(test<T>(0)) == sizeof(one)};
如果T不是内建类型,0就可以隐式转换到T的成员的指针,否则匹配省略号版本。


详细见这里,包含一个更简单的不使用SFINAE实现(代码也更多)is_buildin的方法:
http://www.cppblog.com/Charlib/archive/2009/03/16/76799.html

@李佳
如果只是练习着玩玩,机器码写都没问题。

如果是实际应用上,这么实现这么简单的需求 —— 10行代码了事 ——用到汇编和线程局部存储,那……
有点过了……

别搞了兄弟,用vsprintf之类的函数就可以了。

re: XL Library Preview,诚征指点 OwnWaterloo 2009-11-13 23:57
@溪流
何时需要虚析构函数?当通过父类类指针delete子类时。
String这种类型不应该作为基类,也不应该被多态使用,所以虚析构函数是不必要的。

re: XL Library Preview,诚征指点 OwnWaterloo 2009-11-13 22:03
@溪流
一个虚函数都没有,继承来做啥?

re: 窗口用户数据保存 OwnWaterloo 2009-11-13 17:09
SetProp/GetProp …… 居然还有这种函数……

re: 窗口用户数据保存 OwnWaterloo 2009-11-13 17:05
SetWindowLongPtr(hwnd, i , data );
data = GetWindowLongPtr(hwnd, i );

i 是一个数组的index。
数组大小和窗口注册时填入的cbWndExtra有关。


re: XL Library Preview,诚征指点 OwnWaterloo 2009-11-13 17:01
有个重要的地方忘记说了……
虚析构函数是不需要的

"必须要将fopen或者freopen放到所有变量定义的下面,否则会编译错误..."
C89是不能随处定义自动变量的,只能在函数开始,所有语句之前。
C99和C++允许使用前定义。
可能是C-free(好东西)默认建的是C工程?


win下不是"CONIN$"与"CONOUT$"吗?我记错了?


其实也可以这样:
FILE* fin = fopen("in.txt","r"); /* or fin = stdin */
FILE* fout = fopen("out.txt","w"); /* or fout = stdout */

/*
使用fprintf(fout, format, ... ); fscanf(fin, format, ... );
*/

re: vector的一点疏忽 OwnWaterloo 2009-11-13 02:00
嘿,我也这样载过……
后来我就这么写:
for (size_t i = v.size(); i-- ; )
        visit( v[i] );
 
当然,reverse_iterator也是可行的。
 
re: C++ 资源释放 OwnWaterloo 2009-11-13 01:23
any会使用动态内存,效率比较低。而且,你也不希望看到如下代码:
CSrcRelease ... 产生异常吧?

可以用function<void ()>来保存bind的结果,并在析构函数中调用。
或者,使用Loki::ScopeGuard。

nelem是size_t类型,不是size_t*
不一定是升序,也可以是降序,跟fcmp参数有关。
(void*)&i,(void*)&a是不必要的,(const)T*到const void*的转换可以是隐式的。

re: [转载]ACM技巧——for amateur only OwnWaterloo 2009-11-12 14:38
好像说偏题了……

chinaunix上讨论时,他并没有说是哪一题,只说有题目提示说要用scanf/printf。他自己也记不清楚是哪一题了。
2602是我自己找出来的,觉得这题比较变态。

如果楼主在做其他题目时,发现题目下面有提示说使用scanf/printf的话,还请通知我一下,谢谢~_~
re: 内存池实现 OwnWaterloo 2009-11-12 14:27
同意cm的意见:缓存的层次越少越好。
真要做,就直接与VirtualAlloc, mmap, sbrk交互,不通过crt。


解决内存碎片的算法除了垃圾收集以外,也是存在的。
但这个算法是要client端(内存的使用者)配合才行。
如果内存分配器对内存的请求的方式一无所知,只靠猜测,这种generic内存分配器已经没有提高余地了。
要继续提高内存分配效率,必须让client告诉内存分配器他会以何种方式使用内存。内存分配器根据不同的使用方式来优化自己的算法。

例如,假设实现一种类似<<c interfaces and implementations>>中的arena,并且不通过crt,直接使用VirtualAlloc。当arena被释放的时候,确实就不存在任何碎片。

re: [转载]ACM技巧——for amateur only OwnWaterloo 2009-11-12 00:08
@iSsay
这个嘛,你去测吧,嘿嘿。


做2602的背景是这样的:chinaunix上有人说poj上有题目建议使用scanf/printf,否则做不出来。
然后我就去试了试。 先随便在网上扒了一份代码,TLE……
干脆自己写,用g++提交,结果就过了,换c++提交,第2次就跳到no1去了。
不过oj上的时间测不准,精度太低。其他人多提交几次可能也会冲到no1去。


iostream的格式化是静态分派的,printf/scanf是动态分派。
在格式化上,iostream的机制理论上的效率是会高而不是低。

iostream输在格式化后的其他事情上去了。iostream下还有一层client可知的streambuf层次。

iostream多这一个层次,就将"格式化"与"缓冲"工作分开了。
你可以复用iostream的格式化功能,但给它一个不同于file的目的地,比如socket、memory、null —— 只要传递给它相应的streambuf就行。

对于memory作为目的地,stl提供了stringbuf。并有相应的stringstream在iostream上增加一些接口,使得client不用直接操纵stringbuf。
C标准库相应有sprintf,sscanf。但要这么看,sprintf不能扩容。
类似的还有在我最开始接触vector的时候,也觉得它慢。因为我拿vector和固定大小数组比较。但当我不做oj,数组大小不方便提前计算出时,怎么办?
而且,stl其实还有strstream……

以socket作目的地? printf/scanf怎么搞?
自己实现printf/scanf吗? 你觉得这容易吗?
如果不自己实现printf/scanf,那就只能利用缓存。
拿这种情况和iostream + socketbuf比较,那才公平。

iostream还有很多乱七八糟的功能,locale,expcetion,callback,fillchar……

总之,在一个只处理build-in类型,数组/缓冲大小可以提前计算并按最大值提供,不需要按需提供/扩展,不处理多语言的情况下 —— OJ的情况下 ——确实利用不了iostream,vector等提供的功能。
但OJ做多了,就反过来说它们的不是,就很扯蛋了。
说实话,OJ的代码普遍是上不得台面的,大家自己心里清楚。
根本就没有一点点软件工程的美感在里面。可复用吗?不能,都是一次性筷子,完全是为了AC而已。

在实际开发中,没有这么多美好的前提条件。

即使iostream功能比printf/scanf多得多,如果iostream的格式化比printf/scanf有数量级的差异,没得说,那肯定是iostream实现得太烂……
同样的是格式化和读写文件操作,多一个间接层次就导致效率数量级的下降?那不是写得烂能是什么呢?找个好点的吧。
还有用VC6的OJ(非POJ),你能拿它怎么办呢?

re: [转载]ACM技巧——for amateur only OwnWaterloo 2009-11-11 23:05
@iSsay
标准IO?cin,cout,cerr,clog不就是标准IO么?

你指的是formatted io?

re: XL Library Preview,诚征指点 OwnWaterloo 2009-11-11 22:45
@溪流
一个google帐号好像可以建5个项目。每个项目好像可以有2g空间。但是只能放和代码相关的哦,否则被发现了google帐号会被禁用。

每个项目可以传文件上去,比如打包好的代码。

还有一个repository。原来只提供svn的,后来加入了hg。不过没有加git。
svn的repository就是上面说的那样,拥有者才有commit权限以及授权的权限。
普通用户只有check out的权限。要么只看不改,要么找你要授权,要么给你发补丁。


自己机器上做一个svn repository的事…… 我也这样干过……
所以很痛恨svn,所以打算用git。

re: [转载]ACM技巧——for amateur only OwnWaterloo 2009-11-11 21:26
@iSsay
就事论事而已,我不是大牛,pku上就没过几道题。
代码里面有很多速度测试的代码,所以很长。

其实是用istream::read 一次读完所有输入到buf。
将buf[0],buf[2],buf[4], ... 看作a
将buf[1],buf[3],buf[5], ... 看作b
然后高精度加高精度。
加法时没有没有转换到0-9 直接用'0'-'9'计算,输出时也省去了另一次转换,直接输出一个字符串。

木有
re: XL Library Preview,诚征指点 OwnWaterloo 2009-11-11 20:35
@溪流
别人只能check out不能commit。除非你授权。或者把补丁发给你。
用git吧,趋势……

re: [转载]ACM技巧——for amateur only OwnWaterloo 2009-11-11 20:30
@iSsay
少扯了,uther是我临时注册的马甲。

re: C++完美实现Singleton模式 OwnWaterloo 2009-11-11 10:25
@溪流
嗯嗯,你说中了,炒作~_~
类似的还有很多……

re: [转载]ACM技巧——for amateur only OwnWaterloo 2009-11-11 03:17
"经实践,在大规模输入输出下,cin,cout效率远远低于scanf()和printf()"
远远低于? 太夸张了……
野蛮人拿到打火机可能也会抱怨"还不如我的木头"。

看看这个:
http://acm.pku.edu.cn/JudgeOnline/problemstatus?problem_id=2602

第1个uther的,就是用C++ iostream做的。

re: C++完美实现Singleton模式 OwnWaterloo 2009-11-10 16:05
如果不加保护,两种写法都有可能产生2个实例。

书上采用第2种形式居多的原因,可能是因为Gof的书……
第1种形式是Scott Meyers后来发明的。

re: XL Library Preview,诚征指点 OwnWaterloo 2009-11-10 01:29
@溪流
你就没领会后者的精妙~_~

后者的精妙之处在于:增加的东西不可能轻易拿掉 —— 否则会破坏旧有代码。
反之,加入原本不存在的东西是很容易的事情……

如果某个功能确实很常用,你可以再得到这种反馈之后将其作为aux添加进去。
反之,如果一开始就有某个设计糟糕的功能存在了,你得到反馈之后也很难将其去掉,并且还要一直维护这个糟糕设计…… 很恶心


我很欣赏lua的设计,将lua库分为core和aux两个层次,而不是混淆在一起。
加上client,总共就是3个层次。
保持core的精简对维护是非常重要的。
aux本身实现就不难,多提供一些对维护影响不大。是否提供完全看需求 —— 这是否是很常见的一种使用方式。

以unix的机制、策略论来说:core就仅仅提供机制,aux将一些常用策略打包,方便client使用。


设计之初就要考虑如何将core精简到最小。这对日后维护是非常有帮助的。
一种精简的大方向就是仅提供机制。比如vprintf_parse,就是一种机制。

客户会如何使用它?就是策略了。客户可以非常多的方式(dst不同)使用它。
可以预见:将string作为dst是一种很常见的使用策略。
仍然可以先不提供它…… 万一这种估计错误了呢-_-
如果估计正确,大量代码的使用者向你抱怨"为什么不提供string.format?",你再提供也来得及~

其他的精简方式…… 再慢慢总结吧……

re: XL Library Preview,诚征指点 OwnWaterloo 2009-11-10 01:06
@溪流
1.
这是C++的缺陷…… 当初可能没想到模板会被这么用,所以模板的功能其实还比较弱。
即使比较弱,也比java和C#强大,它是真正的代码生成器……
C#的模板有一些约束,java的根本就是垃圾……
所以,模板还是很复杂的……

更本质的说,其实体现的是一种ducking type,以单一函数作为组件之间交互的接口,而不是整个类型。ruby、python、lua这种动态类型语言都支持ducking type。而C++的模板只支持编译时的ducking type。
C++社区给这种使用方式取了一个新的名字,叫concepts……

ducking type可能属于新东西,而且很可能是意外产物(比如C++、python、lua;ruby好像是设计之初就考虑到这种用法),所以没有提供专门的、显示的通过短小的代码(比如interface声明)就可以表达的方式。只能通过文档了……

说穿了,那些抵触这种设计的,要么是偷懒不想看文档,要么是已经学会OO就不想学任何其他新事物,要么就是理解能力不够……

心里疙瘩放下吧……
1.1. 虽然没有专门的语法支持,但语言还是会检查的,比如C++编译时出错,其他3个语言运行时出错。
1.2. 比如python标准库中,序列就没有单独的size()成员。所有的序列都通过len得到长度。已经开始向这种思想靠拢了。
1.3. stl也这么多年了……



2
我对0依赖的看法不是"难",而是"通常没有必要"。
应该尽可能复用已有的优秀的代码。
尽可能向已有的,还过得去不算垃圾的标准靠拢,而不是自己独立发明一套,结果在实际应用中无法融合。

当然,这和练习编程技巧相抵触……
所以我想提出一些建议,既可以练习;并且练习的结果是可以真正派上用场的。

比如,你可以考虑实现这样一个函数:
int vprintf_parse(void (*handler)(const char* s,void* context),void* context
const char* format, va_list arg );

按vprintf的标准去解析format与arg。每处理完一个%就调用handler一次。
由handler去考虑将s"输出"到哪里。
这样的话,vprintf_parse就可以用于很多很多地方:传递不同的hanlder给它就行。
当然,你也可以用它来实现string.format。 但一定要将vprintf_parse暴露出来,否则窝在string.format中太暴殄天物了。


更进一步…… 还可以提供一些让客户代码扩展的机制,让它自己定义%后的转义符,以及处理方式。



3
我的意思是,这种方式是行不通的。
你要插入的元素是T吧?
std::set<std::list<T> > 元素是 std::list<T> 哦, 不是T了。
比较也是按std::less<std::list<T> >比较,而不是T。

不管multiset的底层实现是rbtree还是rbtree+list,都需要真正定义一个类,将底层实现的接口adapt一下才行。仅仅typedef是不够的……

re: XL Library Preview,诚征指点 OwnWaterloo 2009-11-09 23:57
再给你说个玄乎一些,不那么实际的理论吧……

一种设计倾向是"添加直到无法添加"。
一种设计倾向是"减少直到无法减少"。

我倾向于后者。也相信你写过一些代码之后会对前者感到反感。

re: XL Library Preview,诚征指点 OwnWaterloo 2009-11-09 23:43
1.
"尽管很“巧合”有几个一样的接口"
stl组件之间的通信就是通过这种"巧合"。


2.
为什么要零依赖? 这个需求很怪……

想练习发明轮子的心情可以理解……
再给你提供一个练习而又不是重复发明的东西吧:
将printf和scanf的解析过程抽象出来。
这样,string就只是管理内存就可以了。
format交给别的地方去做。
相互之间保持正交。

这样,format的src和dst可以是FILE*,socket, 以及任何可扩展长度的顺序结构,比如各种string,std::vector,std::deque,std::list。
不要将format的功能"埋葬"到你那个string中,太可惜了。将它剥离出来。


还有stl中的反向迭代器其实是有单独一个模板的,在<iterator>中,通常不需要自己手工编写。
你可以重复发明它一次,然后应用于你的各种容器之上,而不是重复发明多次。



3.
至少std::multiset<T>和 std::set<std::list<T> > 或 std::set<std::vector<T> > 语意都是不同的。

@溪流
好像是这样的…… 很尴尬……

RbTree和Set还好一些,因为它们的接口不一定相同,可能真的需要用RbTree实现Set,并增加或隐藏一些成员。

我以前遇到的情况是实现了一个allocator,然后想运用到STL的容器当中去,发现了这个问题……

下面这种想当然的代码行不通:
template<typename T>
typedef std::vector<T,my_allocator<T> > my_vector;

而且my_vector和vector行为完全相同。不像RbTree,本来就需要Set去adapt一下。比如下面3种代码,都很恶心:

1.
template<typename T>
my_vector : public std::vector<T,my_allocator<T> > {};

2.
template<typename T>
my_vector : std::vector<T,my_allocator<T> > {
// forwarding functions
};

3.
template<typename T>
my_vector {
std::vector<T,my_allocator<T> > v_;
// forwarding functions
};


后来想想,算了,我的工作就是提供allocator,不负责为其取一个好听的名字。
敢用allocator的人,肯定知道应该这么用:
std::vector<his_element,my_allocator<T> > v; //一个使用了my_allocator的std::vector。
同样工作得很好嘛。



相反,使用c++0x的功能,可能还会造成一些问题:
my_vector<int> v; // my_vector是什么东西?

哦,看到这些代码,才能明白它是什么东西:
template<typename T>
using my_vector = std::vector<T,my_allocator<T>>;


这和typedef的误用会过多引入不必要的概念是一个道理。

C++0x可以...
好像叫template alias

@bujiwu
map.erase有3个重载
...
返回iterator的erase是不符合STL标准的。
Windows还是linux没有直接关系。于STL实现有直接关系。
map.erase有3个重载:
void erase ( iterator position );
size_type erase ( const key_type& x );
void erase ( iterator first, iterator last );

返回iterator的erase是不符合STL标准的。

re: GetPidByHandle OwnWaterloo 2009-10-30 23:14
DWORD GetProcessId(HANDLE process); ???

re: 如何为软件源码产品选择授权 OwnWaterloo 2009-10-29 01:24
@空明流转
谢谢~_~
re: 如何为软件源码产品选择授权 OwnWaterloo 2009-10-28 16:30
请教一下:
"但是如果你使用、修改了别人LGPL协议的源代码,那么,修改后的源代码就必须要公开,并且一样遵守LGPL协议。"

假设这样一个场景,一个库L,使用LGPL。
某个家伙,比如我吧,对这个库作了一些修改,成为L1,并且使用L1做了一个应用程序,叫A1。

必须公开的部分是L1,还是L1+A1 ?


我觉得后者好像说不过去。
因为我总可以将我做的事情分成2步:
1. 发布一个使用LGPL的L1 // 必须公开L1代码
2. 使用LGPL的L1产生A1 // 貌似不必公开A1代码?

是这样吗? 谢谢~_~

代码很好看。

GetN(int n)始终返回1? 复制时弄错了?
@Little star
标准就这么规定的。

《C 语言常见问题集》 5.14中介绍了一些古怪的空指针。
“至少PL/I, Prime 50 系列用段07777, 偏移0 作为空指针。
……
CDC Cyber 180 系列使用包含环(ring), 段和位移的48 位指针。多数用户
(在环11 上) 使用的空指针为0xB00000000000。
在旧的1 次补码的CDC 机器上
用全1 表示各种数据, 包括非法指针, 是十分常见的事情。
Symbolics Lisp 机器是一种标签结构, 它甚至没有传统的数字指针; 它使用
<NIL, 0> 对(通常是不存在的<对象, 偏移> 句柄) 作为C 空指针。


浮点如果是采用IEEE754, 0.0恰好是二进制全0。
但标准没有保证浮点数一定采用IEEE754。

@Little Star
class C {
/* data declaration */
public:
C() { memset(this,0,sizeof(*this); }
};

改为:
class C {
struct data {
/* data declaration */
} data_;
public:
C() { memset(&data_,0,sizeof(data_); }
};


还是需要注意memset( ... 0 ... );
不能保证: 指针是nullptr,浮点数是0.0, 0.0f, 0.0lf。
能保证:整数是0, 字符是null字符,即'\0'。

@codejie
STL有输入、输出、前向、双向、随机,5种迭代器。
erase有范围删除:
first = v.begin()+start;
v.erase( first, first+min(size,v.size()-start) );

没有虚函数也不可以乱来。
空指针并不一定是二进制全0。

1.
char* label = 0;

2.
char* label;
memset(&label,0,sizeof(label) );

有平台上两者功能不同。

晕……
v.erase(v.begin()+1);

re: 虚拟键盘(软键盘)设计要点 OwnWaterloo 2009-10-19 00:11
1.要搜kbcwait4ibe,不要搜"虚拟键盘"。
2.以下划线开始的标识符是C/C++语言所保留的啊,同学们……
具备你说的那些能力后,想读研又是麻烦事了……
会成天想着具备更多的能力,然后成绩一塌糊涂……
学校是认成绩(以及关系)而不是能力的地方……

re: 优先级队列 OwnWaterloo 2009-10-18 18:13
删去最大最小值(O(1)) ???

删除操作不包括shift? 不shift的话,剩下的就不是堆了。
删除操作包括shift,复杂度就是对数。


re: ACM中java的使用 OwnWaterloo 2009-10-17 00:04
java的慢,不仅仅是在编译上,而是在其内存模型上。
即使有JIT也没用,再优化JIT也没有用。除非修改其内存模型。
但那是不可能的。

java效率媲美C/C++的实际例子:
要么是是在emulator层上跑C/C++代码;
要么是例子过于简单以体现不出java的缺陷;
要么两者兼有。

说java效率可以C/C++媲美的人,要么是奸商,要么是sb。
re: ACM中java的使用 OwnWaterloo 2009-10-16 19:46
哎…… 懒得批了……
有假设就写到代码里嘛。
随便找个编译单元:
static char assume[sizeof(header)==sizeof(u16)*3?1:-1];

或者就在header下方写:
typedef int assume[sizeof(header)==sizeof(u16)*3?1:-1]];

共10页: First 2 3 4 5 6 7 8 9 10 
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用链接

留言簿(8)

随笔档案(16)

链接

搜索

  •  

积分与排名

  • 积分 - 194904
  • 排名 - 132

最新随笔

最新评论

阅读排行榜

评论排行榜