A*******e 发帖数: 2419 | 1 vector v = {4, 3, 2, 1}
set s1(v.begin(), v.end());
set s2({v.begin(), v.end()});
s1/s2的初始化都可以编译通过。s2没有必要,但s2到底调用了哪些ctor呢? |
s*****t 发帖数: 89 | 2 objdump一下就知道了
【在 A*******e 的大作中提到】 : vector v = {4, 3, 2, 1} : set s1(v.begin(), v.end()); : set s2({v.begin(), v.end()}); : s1/s2的初始化都可以编译通过。s2没有必要,但s2到底调用了哪些ctor呢?
|
A*******e 发帖数: 2419 | 3 源码,用哪个选项能看函数调用?
#include
#include
using namespace std;
int main() {
vector v = {4, 3, 2, 1};
set s1(v.begin(), v.end());
set s2({v.begin(), v.end()});
}
【在 s*****t 的大作中提到】 : objdump一下就知道了
|
s*****t 发帖数: 89 | 4 1:g++ -std=c++11 -g -o test test.cpp
2: objdump -S test |c++filt | less
找到你想找的函数(main)然后看看的call,结果大概是这个样子:
http://pastebin.com/Xr9p4DcC
补充:
- objdump :-S能够把代码 inline到汇编里面,-d(-D)只能反汇编
- 不用c++filt标准库的符号很难看, |
A*******e 发帖数: 2419 | 5 这结果还是看不出哪个ctor被调用啊。
我最后用土办法,带花括号和不带花括号的版本分别编译,比较生成的目标文件,结果
是一样的。
疑问:set(v.begin(), v.end())和set({v.begin(), v.end()})为何是一回
事呢?
第二个到底是怎么编译的?
【在 s*****t 的大作中提到】 : 1:g++ -std=c++11 -g -o test test.cpp : 2: objdump -S test |c++filt | less : 找到你想找的函数(main)然后看看的call,结果大概是这个样子: : http://pastebin.com/Xr9p4DcC : 补充: : - objdump :-S能够把代码 inline到汇编里面,-d(-D)只能反汇编 : - 不用c++filt标准库的符号很难看,
|
g*********e 发帖数: 14401 | 6 这些都是C11新加的写法吧 语法糖而已
【在 A*******e 的大作中提到】 : 这结果还是看不出哪个ctor被调用啊。 : 我最后用土办法,带花括号和不带花括号的版本分别编译,比较生成的目标文件,结果 : 是一样的。 : 疑问:set(v.begin(), v.end())和set({v.begin(), v.end()})为何是一回 : 事呢? : 第二个到底是怎么编译的?
|
l*********s 发帖数: 5409 | 7 还是不懂。
【在 g*********e 的大作中提到】 : 这些都是C11新加的写法吧 语法糖而已
|
d****i 发帖数: 4809 | 8 应该坚决反对s2的这种写法,根据manpage:
http://www.cplusplus.com/reference/set/set/set/
set s1(v.begin(), v.end());
就是用的两个iterator[first, last)的用法,清晰简单明了。而s2的话违反了数学上
定义一个集合的基本notation,就是一个集合应该写成
A = {a1, a2, ...., a_N}
而s2显然是混为一谈,把{}作为两个iterator的起点和终点来初始化定义了,这个和数
学的notation完全相背。所以s2是完全错误的用法。
【在 A*******e 的大作中提到】 : vector v = {4, 3, 2, 1} : set s1(v.begin(), v.end()); : set s2({v.begin(), v.end()}); : s1/s2的初始化都可以编译通过。s2没有必要,但s2到底调用了哪些ctor呢?
|
n******n 发帖数: 12088 | 9 s1是调用range ctor
set s3{v.begin(), v.end()}也是调用range ctor,但是通过uniform initialization。
s2就看不懂了。花括号调用range ctor,圆括号调用copy ctor,然后来个copy
ellision?
【在 d****i 的大作中提到】 : 应该坚决反对s2的这种写法,根据manpage: : http://www.cplusplus.com/reference/set/set/set/ : set s1(v.begin(), v.end()); : 就是用的两个iterator[first, last)的用法,清晰简单明了。而s2的话违反了数学上 : 定义一个集合的基本notation,就是一个集合应该写成 : A = {a1, a2, ...., a_N} : 而s2显然是混为一谈,把{}作为两个iterator的起点和终点来初始化定义了,这个和数 : 学的notation完全相背。所以s2是完全错误的用法。
|
l*********s 发帖数: 5409 | 10 别扯没用的,说说为啥s2能work吧,偶也很好奇。
【在 d****i 的大作中提到】 : 应该坚决反对s2的这种写法,根据manpage: : http://www.cplusplus.com/reference/set/set/set/ : set s1(v.begin(), v.end()); : 就是用的两个iterator[first, last)的用法,清晰简单明了。而s2的话违反了数学上 : 定义一个集合的基本notation,就是一个集合应该写成 : A = {a1, a2, ...., a_N} : 而s2显然是混为一谈,把{}作为两个iterator的起点和终点来初始化定义了,这个和数 : 学的notation完全相背。所以s2是完全错误的用法。
|
|
|
d****i 发帖数: 4809 | 11 这不是有用没用的问题,是基本原则问题。set的构造函数并没有这样的转意,直接用
range constructor两个iterator非常简单清楚,为什么要去画蛇添足的绕?
【在 l*********s 的大作中提到】 : 别扯没用的,说说为啥s2能work吧,偶也很好奇。
|
l*********s 发帖数: 5409 | 12 curiosity is a cardinal virtue for programmers. There is a mystery, do you
want to figure it out, don't you?
【在 d****i 的大作中提到】 : 这不是有用没用的问题,是基本原则问题。set的构造函数并没有这样的转意,直接用 : range constructor两个iterator非常简单清楚,为什么要去画蛇添足的绕?
|
d****i 发帖数: 4809 | 13 Remember: Simple Is Beautiful. Using s2 is a bad example of violating this
principle.
【在 l*********s 的大作中提到】 : curiosity is a cardinal virtue for programmers. There is a mystery, do you : want to figure it out, don't you?
|
n******n 发帖数: 12088 | 14 我想讨论的本意并非是最佳实践,而是对C++11和编译器的理解。没有人会写s2吧。
【在 d****i 的大作中提到】 : 这不是有用没用的问题,是基本原则问题。set的构造函数并没有这样的转意,直接用 : range constructor两个iterator非常简单清楚,为什么要去画蛇添足的绕?
|
n******n 发帖数: 12088 | 15 一楼已经说了,s2没有必要。你是说,既然没有必要这么写,就没必要搞清楚为何编译
通过吗?我倒觉得这些生僻写法的讨论能帮助理解C++
【在 d****i 的大作中提到】 : Remember: Simple Is Beautiful. Using s2 is a bad example of violating this : principle.
|
s*****t 发帖数: 89 | |
n******n 发帖数: 12088 | |
s*****t 发帖数: 89 | 18 我觉得不看规范去猜也讨论不出什么结果,既然gcc和clang都认就大概能说明这个行为
是标准定义了的,翻到规范的8.5.1看看语法定义:
initializer:
brace-or-equal-initializer
( expression-list )
brace-or-equal-initializer:
= initializer-clause
braced-init-list
initializer-clause:
assignment-expression
braced-init-list
initializer-list:
initializer-clause ...opt
initializer-list , initializer-clause ...opt
braced-init-list:
{ initializer-list ,opt }
{}
可以看到{}内的东西最后就是initializer-list,opt
语义定义在202页,if otherwise包围的地方这么说的:
If the destination type is a (possibly cv-qualified) class type:
If...
Otherwise ,user-defined conversion sequences that can convert from the
source type to the destination type or (when a conversion function is used)
to a derived class thereof are enumerated as described in 13.3.1.4, and the
best one is chosen through overload resolution ,The function selected is
called with the initializer expression as its argument; if the function is a
constructor, the call initializes a temporary of the cv-unqualified version
of the destination type. The temporary is a prvalue
这样解释了为什么s2调用了和s1一样的constructor |
n******n 发帖数: 12088 | 19 没看懂怎么解释了。这里的要点是overloading resolution,以及为何解析到range
ctor
【在 s*****t 的大作中提到】 : 我觉得不看规范去猜也讨论不出什么结果,既然gcc和clang都认就大概能说明这个行为 : 是标准定义了的,翻到规范的8.5.1看看语法定义: : initializer: : brace-or-equal-initializer : ( expression-list ) : brace-or-equal-initializer: : = initializer-clause : braced-init-list : initializer-clause: : assignment-expression
|
n******n 发帖数: 12088 | 20 cppreference.com说的很清楚。
【在 n******n 的大作中提到】 : 没看懂怎么解释了。这里的要点是overloading resolution,以及为何解析到range : ctor
|
g*********e 发帖数: 14401 | 21 应该是c11编译器提供的convenient method吧
【在 A*******e 的大作中提到】 : 这结果还是看不出哪个ctor被调用啊。 : 我最后用土办法,带花括号和不带花括号的版本分别编译,比较生成的目标文件,结果 : 是一样的。 : 疑问:set(v.begin(), v.end())和set({v.begin(), v.end()})为何是一回 : 事呢? : 第二个到底是怎么编译的?
|