V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  zzxxisme  ›  全部回复第 1 页 / 共 1 页
回复总数  18
2022-03-18 19:06:16 +08:00
回复了 ActualAvocado 创建的主题 C++ [C++]为什么 For 循环在调试时执行顺序像个悠悠球?
我猜反向执行是在执行 string 和 vector 的析构函数。可以试着回去的时候看看能不能 step in ?
2022-01-31 01:50:38 +08:00
回复了 amiwrong123 创建的主题 C++ 项目中这样去隐藏类的真正实现 是种好的做法吗?
先说我认为的结论:这种写法的主要目的 并不是 为了隐藏实现,而是为了方便转移、复制、释放一个 ModuleBase 子类的对象。

首先我们有 ModuleBase 这个基类,这个基类可能有很多种不同的子类实现,例如 ModuleBaseImpl 是其中一种实现。但是我用这个 Module 的时候我可能不关心具体实现是怎么样,不关心具体的子类是什么。我只想拿到 ModuleBase 的基类的指针(或者引用)进而能够访问子类的具体实现就好了。如果只是这个需求,我的设计可能就是令到 ModuleBase 的虚函数全部都弄成 纯虚函数 (也就是没有默认实现),然后子类 ModuleBaseImpl 必须实现所有纯虚函数。也就是

```c++
class ModuleBase {
...
virtual void startTimer(int32_t timerId, uint64_t msec) = 0; // 纯虚函数
};

class ModuleBaseImpl : public ModuleBase {
...
void startTimer(int32_t timerId, uint64_t msec) override {
... // 具体实现
}
};
```

然后这样会有一个小问题,就是我用一个 Module 的时候,我必须用 ModuleBase 的指针(或者引用,但如果能用引用,可能就没有我说的这个小问题)。而且用这个指针我还要注意适当的时候 delete 这个指针。但是如果这个指针是被其他人用的,在其他人的函数里面他们未必会 delete 这个指针。所以这个时候我需要弄多一个类,来包装这个 ModuleBase 指针,也就是

```c++
class ModuleBaseWrapper {
~ModuleBaseWrapper() { delete module; ​}
private:
​ModuleBase* module;
};

```

有了这个 ModuleBase Wrapper 之后,这个 Wrapper 在析构的时候会帮忙析构这个 ModuleBase 指针。

最后,回到一开始你说的 ModuleBase 里面包含了一个 android::sp<ModuleBase>impl 的事,这个 android::sp<ModuleBase>使得 ModuleBase 可以当做上面的 ModuleBaseWrapper 来用。
@ShikiSuen
> 我重写了逐行处理的版本,倒是成功了。
Congratulation!

0.0 然后有一些小建议。我看你现在的做法是把整个文件读到了内存,我不确定你的文件的大小怎么样,如果文件太大的话,这样其实会占用很多内存,而且本身没有必要一下子把所有行都放到内存再处理。其实你可以在
getline(zfdFormatConsolidatorIncomingStream,zfdBuffer);
拿到一行之后马上就去 regex_replace 你读到的行。另外 regex_replace 的那个地方,其实也没有必要用 c_str(),直接
vecEntry[i] = regex_replace(vecEntry[i], sedWhiteSpace, " ")
反而可能会更好。
@ShikiSuen 我对 C++的 std::regex 真的不熟,它的语法应该是这里提到的 https://en.cppreference.com/w/cpp/regex/ecmascript ,这里面没有提到\h ,所以应该是不支持的。

ObjCpp 和 C++ 是两门不同的语言,ObjCpp 我就完全不懂了…

不过如果可以选择其他语言的话,用自己更擅长的语言会更好 0.0
@ShikiSuen 这样我建议你从文件(也就是档案) zfdFormatConsolidatorIncomingStream 里面一行一行的读进来,每次 regex_replace 处理一行然后输出到新的文件 zfdFormatConsolidatorOutput 。

你可能会问,我能不能改一下 regex 的规则,让它不删除\n 就好了?是可以试着改成"[^\\S\r\n]+",这里\\S 就是所有 非空格字符,\\S\r\n 就是所有非空格加上换行,[^\\S\r\n]就是对“所有非空格字符和换行字符”取反,就变成了“除去换行字符的所有空格字符”。但是这会有一个不好的地方,对于"a \nb",它的替换结果还是"a \nb",而不是“a\nb”,因为这个空格不是 leading 或者 tailing 的空格,所以是被压缩成一个而不是去掉。所以我建议的是读一行处理一行。
@Inn0Vat10n 说的那个 c_str(),只是有点奇怪,但不至于非法。zfdBuffer 它是一个 std::string ,regex_replace 返回的也是一个 std::string ,对 std::string 取 c_str()得到一个 const char*,这样最终就是把一个 const char* 赋值给 std::string ,会把 const char*复制一遍到 std::string 的。我觉得奇怪只是说,c_str()其实是不需要的。

@ShikiSuen 我当初测试用的是这个例子
```c++
std::string zfdBuffer = " \t123 456\t\n789 \taaaa ";
std::cout << '@' << zfdBuffer << '@' << std::endl;
std::regex sedWhiteSpace("\\s+"), sedLeadingSpace("^\\s+"), sedTrailingSpace("\\s+$");
zfdBuffer = std::regex_replace(zfdBuffer, sedWhiteSpace, " ");
zfdBuffer = std::regex_replace(zfdBuffer, sedLeadingSpace, "");
zfdBuffer = std::regex_replace(zfdBuffer, sedTrailingSpace, "");
std::cout << std::endl << '@' << zfdBuffer << '@' << std::endl;
```

它的结果是会把空格,\t ,\n 这些去掉或者合并成一个空格的。所以我觉得原来 regex_replace 的问题应该是解决了的。
```
@ 123 456
789 aaaa @

@123 456 789 aaaa@
```

> 但 Xcode 编译出来之后我发现我这 txt 档案的内容会被清空
我猜可能是其他方面的问题。或者你在第一个 regex_replace 之前把 zdfBuffer 打印出来看是什么内容,然后在最后一个 regex_replace 之后再把 zdfBuffer 打印出来看是什么内容,进行对比?
std::regex 的语法好像比较特别。不太常用不太熟,但是我改成下面的 regex 好像是可以的。

```c++
regex sedWhiteSpace("\\s+"), sedLeadingSpace("^\\s+"), sedTrailingSpace("\\s+$")
```
2022-01-28 03:03:42 +08:00
回复了 amiwrong123 创建的主题 C++ std::move 的实现使用到了万能引用?
> 但是我经过了 vs2019 debug 后,发现 c 的类型为 A&&,这是为什么呀?

这个不太清楚怎么回答。我觉得因为你是用 auto&&去接 returnTemp()产生的临时变量,所以 c 的类型就是 A&&。如果你使用 auto 去接,那 c 的类型就是 A 。但我觉得不管 c 的类型是 A&&还是 A ,它都是维持着 A 类对象的一份 local copy ,用起来都是一样。

> _Ty& _Arg 优先级比 _Ty&& _Arg 高

这个我觉得是有条件的。如果参数本身是 A&这样的引用类型,那_Ty& _Arg 有更高的优先级。如果参数是 A 或者 A&&这样的,_Ty&&有更高的优先级。
2022-01-27 02:11:37 +08:00
回复了 amiwrong123 创建的主题 C++ std::move 的实现使用到了万能引用?
再插一句,如果你把第二个 fun_test 改成
```
template <class _Ty>
void fun_test(_Ty _Arg) { // 这里把&去掉
cout << "left" << endl;
}
```
那么 fun_test(_Ty&&)和 fun_test(_Ty)在匹配 fun_test(a)的时候,编译器会选不出来而报错,因为这两个函数面对 A&的 rank 一样。
2022-01-27 02:07:18 +08:00
回复了 amiwrong123 创建的主题 C++ std::move 的实现使用到了万能引用?
@amiwrong123
> 所以,std::move 只有这一个实现也能正常工作,因为它什么类型都可以接,是吧。附言里我加的这个问题,为什么有了万能引用版本的函数,还能调用到左值引用版本的函数呀?有点不理解了,老哥

这里有两点吧。一个是 _Ty&& 的那个的确能接住所有类型。另一个是,当你还写了一个 _Ty& 版本的函数的情况下,因为 main 函数里面的 fun_test(a)传进去的是 a 的引用,也就是传进去的是 A&,这个情况下,编译器会认为 _Ty& 版本的 fun_test 会比 _Ty&& 版本的 fun_test 有更高的 rank (优先级)去匹配这个 A&。所以正确的说法我觉得是,_Ty&&能够接住所有类型,但是在有其他重载的情况下,_Ty&&不一定有更高的 rank 被用上。你可以看看 https://en.cppreference.com/w/cpp/language/overload_resolution 的 Ranking of implicit conversion sequences 下列举的不同情况。

> 上面这个程序是不是就是你说的意思? constexpr 函数可以赋值给 constexpr 标识符,也可以赋值非常量的标识符(如上程序)
对的。你也可以看看这里最下面给的一些例子: https://en.cppreference.com/w/cpp/language/constexpr
2022-01-26 23:03:39 +08:00
回复了 amiwrong123 创建的主题 C++ std::move 的实现使用到了万能引用?
尝试回答一下:
1. 利用_Ty&&可以接受所有引用类型。如果是左值引用,例如 int&,那么这里"_Ty"就是"int&",整个"_Ty&&"就是"int& &&"。如果是右值引用,例如 int&&,那么_Ty 就是 int 。如果传的是一个值,例如 int ,这样_Ty 也是 int 。
2. std::move 加一个 constexpr 并不意味着返回值一定要加 const ,这个是对函数加的 constexpr ,它意味着这个 std::move 可以在用在一个 constant expression 里面,这样,编译器可以在编译期间进行这个 move 。这个 constexpr 是 c++17 之后加进来的,std::move 是 c++11 就加进来的,我猜可能你看过一些版本是 c++17 之前的?
感觉有几个思路…
1. 首先看自己喜欢哪个方面哪个方向的技术,然后看这个方向有什么可以分享的,这样顺带可以自己学习一波。
2. 自己工作做开的内容是属于哪个方面的,然后从这个方面找相关的技术分享,这样工作量比较轻松。
3. 从别人分享的内容看属于哪个方向的,然后找相关的东西分享。例如 Disruptor 是属于多线程消息传递无锁队列,然后属于这方面的有没有可能更好的队列,然后找到这个 https://github.com/rigtorp/MPMCQueue
2021-10-10 23:44:16 +08:00
回复了 olist 创建的主题 程序员 今天看到一个新发现的有趣的排序算法。
1. 这个论文里面提到这个 新算法 的好处不是在于效率,而是在于它的简单性,以及它的 看上去不是那么正确 的特点,然后这个论文去证明它的正确性。这个算法的确最后把 A 数组进行了升序排序。
2. 你说的第二个算法不是传统认为的冒泡… 冒泡每次 swap 的是相邻的两个数,而你的第二个算法是为`A[i]`找`A[i .. n]`的最小值。
2021-08-30 22:18:28 +08:00
回复了 icemanpro 创建的主题 C++ 如何将 list 的值传给函数的可变参数?
看了其他人的理解,我觉得问题是把一个 list 的所有元素传到一个函数的参数列表,而函数的参数列表是 C 的可变参数。我想的是,既然是传给函数作为参数,list 的长度(也就是参数的数目)应该假设不会很多,于是可以假设一个最大 list 长度。如果是利用 C++,可以写一个模板函数,通过递归的方法一下下把每个元素取出来并用 parameter pack 存着,把所有都拿到之后,然后传给带可变参数的函数。像 5 楼说的,用 parameter pack 要在编译期间确定长度,这个长度就是前面说的最大 list 长度。

然后试着写了一下: https://gist.github.com/zzxx-husky/40a42457c01b86f388974a14278dc78e
2021-08-30 18:21:44 +08:00
回复了 icemanpro 创建的主题 C++ 如何将 list 的值传给函数的可变参数?
这个问题问得不知道怎么回答,因为描述不清楚,可以有很多种理解,例如是把整个 list 当做一个参数传给函数,还是把 list 的每个元素拿出来传给函数的每个参数?你的 list 和函数的签名是怎样的?最好能给段代码来表明你要做的事情,还有你做过什么样的尝试,这些尝试有什么问题。
2021-08-27 19:54:13 +08:00
回复了 Hconk 创建的主题 C++ 看到一段挺有意思的 C++代码
尝试说一下我的理解。
1. 首先 [](){} 这样就是创建了一个 不接受任何输入,什么都不做,没有任何输出的 lambda
2. 然后 [](){} () 就是调用了一下上面说的 lambda

剩下的就是在加 attributes

3. lambda 声明返回值类型的地方是可以加 attribute 的,例如加一个[[noreturn]]就是 []() [[noreturn]] {}。而 [[ ]] 就是…加 0 个 attribute 。
4. 大括号里面的执行体里面也可以加 attribute,而且可以一次加多个,例如同时加 likely, fallthrough 就是 [[ likely, fallthrough ]]。而 [[ , , , ]] 就是…什么 attribute 也没有加。
5. 找了一份 C++ standard draft 看了一下 lambda expression 的定义,捕捉列表和参数列表应该是不可以加 attribute 的。我找的是这份 draft: https://eel.is/c++draft/expr.prim.lambda#nt:lambda-specifiers,可以看到 lambda-introducer (也就是捕捉列表)和 parameter-declaration-clause (就是 lambda-declarator 里面)之间是没说可以放东西的。
2021-08-03 11:21:06 +08:00
回复了 zzxxisme 创建的主题 C++ 迫于生计,分享一个自己的 C++ LINQ API 实现
@c0xt30a 是 lazy 的。针对你的例子,
1. 第一个遍历 container 的操作就是翻译成

for (auto& i : container) {
...
}

2. 第二个 take_first(3)的操作是翻译成

num = 3
...
if (num-- != 0) {
...
} else {
break
}
...

3. 第三个 max_reduce 的操作就是翻译成

max = std::nullopt
...
if (!max || *max < x) {
max = x
}

然后把所有逻辑嵌套起来之后,就是下面这样:

num = 3
max = std::nullopt
for (auto& i : container) {
if (num-- != 0) {
if (!max || *max < i) {
max = i
}
} else {
break
}
}

按照你的例子,我弄了一个新的 example ( https://github.com/zzxx-husky/coll/blob/master/examples/first_n_max.cpp )。虽然不是遍历一个 container,但是也是试图 生成 很多的整数。因为只需要从前 3 个里面找,所以最后其实只生成了 3 个整数。下面是在 WSL 上运行 3 次的结果。

zzxx@zzxx:~/repos/coll/release | master
$ time ./examples/FirstNMax
Int 1 is 463223032
Int 2 is 1934040530
Int 3 is 897990617
The max of the 3 ints is 1934040530

real 0m0.010s
user 0m0.000s
sys 0m0.016s

zzxx@zzxx:~/repos/coll/release | master
$ time ./examples/FirstNMax
Int 1 is 2009885599
Int 2 is 491657854
Int 3 is 58190656
The max of the 3 ints is 2009885599

real 0m0.010s
user 0m0.000s
sys 0m0.000s

zzxx@zzxx:~/repos/coll/release | master
$ time ./examples/FirstNMax
Int 1 is 1704636435
Int 2 is 1382089679
Int 3 is 1782466259
The max of the 3 ints is 1782466259

real 0m0.010s
user 0m0.000s
sys 0m0.000s
2021-08-03 03:07:42 +08:00
回复了 zzxxisme 创建的主题 C++ 迫于生计,分享一个自己的 C++ LINQ API 实现
@3dwelcome 谢谢!其实我做的也不是编程语言层面的东西。我用的也是 C++提供的语法,做一些 api 层面的东西,期望 api 可以想例如 scala 那样的 collection api 的函数式 api 好用,同时性能达到最好。
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4284 人在线   最高记录 6543   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 22ms · UTC 01:03 · PVG 09:03 · LAX 18:03 · JFK 21:03
Developed with CodeLauncher
♥ Do have faith in what you're doing.