/home/aleksandr/
I'm understood, thank you)
/home/aleksandr/
It `s Magic
Alex
It `s Magic
Python is magic. C++ is closer to hardware
/home/aleksandr/
)))
Alex
that`s why c++ is faster, it should not check validity of the index like python
/home/aleksandr/
Thanks
Ибраги́м
https://www.youtube.com/watch?v=A3_xrqr5Kdw
MᏫᎻᎯᎷᎷᎬᎠ
https://www.youtube.com/watch?v=A3_xrqr5Kdw
Why just not use if constexpr in the destructor itself lool
Ибраги́м
No it's not
p[1] == *(p + 1); Oh yeah it is ?
Tokin
Btw #ot is there a Comp Sci group?
Ибраги́м
MᏫᎻᎯᎷᎷᎬᎠ
You're an absolute filth my friend.
That's why I'm your friend :D
MᏫᎻᎯᎷᎷᎬᎠ
Nah I mean seriously, why?
vinícius*
but it is, though
vinícius*
array notation is syntax sugar for pointer arithmetic
Anonymous
Array is not a pointer Array just DECAYS to pointer
Àkàßh
I agree
vinícius*
Array is not a pointer Array just DECAYS to pointer
meh, per the C standard: Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
vinícius*
"X is not Y, it is *converted* at compile-time to Y" is true for any syntax sugar ev4r
Ибраги́м
That's why I'm your friend :D
If this is not an absolute filth, don't know what it is. struct data_t { constexpr ~data_t() { if constexpr (std::is_trivially_destructible_v<data_t>) { } else { } } };
Anonymous
but it is, though
1) int arr[2]; int* ptr = arr; assert(sizeof(arr) == sizeof(ptr)); // always false 2) template <typename T, size_t N> size_t size(T (&)[N]) { return N; } size(arr); // 2 size(ptr); // compiler error 3) std::is_same_v(decltype(arr), decltype(ptr)) // false
Ибраги́м
Nah I mean seriously, why?
Because u made a good point above. We don't even know what C++ supports anymore since C++14.
vinícius*
then again
vinícius*
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.
vinícius*
Is it C?
yeah, I'm not talking about C++
Anonymous
I'm talking about C++
Ибраги́м
Ибраги́м
It will be wrong to make that statement with a full-stop.
Anonymous
Why I put a '?' hehe.
I thought it's a sarcasm..
Ибраги́м
I thought it's a sarcasm..
Nah, I can't believe array == pointer, at least not in C++ sense. sizeof() taught me the hard way. Imagine getting 8 for an array 20 elements.
Ибраги́м
See, it's simple
Quite simply, too easy.
Ибраги́м
See, it's simple
struct lunatic_t { constexpr ~lunatic_t() { if constexpr (!std::is_trivially_destructible_v<lunatic_t>) { // Use artillery this time } else { // C4 ? } } };
Ибраги́м
Destruction only happens once here
Anonymous
I meant recursion inside a compiler
Anonymous
lunatic_t is not complete at the point of the usage So how can you tell is it trivially destructible or not?
olli
Why just not use if constexpr in the destructor itself lool
because you want your type to be trivially destructible if possible, defining the destructor makes it non trivial.
olli
~T(){} Still trivial, isn't it?
no, only the default one is trivial... ~T() = default;
olli
You can still end up with ~T(){} with an empty else{} block.
struct NTD { ~NTD() {} }; int main() { static_assert( std::is_trivially_destructible_v<NTD>, ""); } generates <source>:10:5: error: static_assert failed due to requirement 'std::is_trivially_destructible_v<NTD>' "" 1 error generated.
olli
however this is fine struct TD { ~TD() = default; }; int main() { static_assert( std::is_trivially_destructible_v<TD>, ""); }
Ибраги́м
olli
> if all is true: not user provided doing ~T() {} provides and defines a destructor
Eliézer
guys could someone help me doing a webSocket but I connected the signals but dps that he gives it open he does not fall into any signal, the code link is below if anyone can help me I will be very grateful https://pastebin.com/KiDYVJX0
olli
Then olli Why so focusing on this destructor trait(trivial) or in general with types What is so useful about it?!
In this case is not necessarily related to the language itself but rather to the popular ABI(s). Looking at the System V ABI Spec [1] it states in 3.2.3 #2 ". If a C++ object has either a non-trivial copy constructor or a non-trivial destructor, it is passed by invisible reference" and adds as footnote "An object with either a non-trivial copy constructor or a non-trivial destructor cannot be passed by value because such objects must have well defined addresses. Similar issues apply when returning an object from a function". As implication even small types can't be passed in a register but a reference to them need to be passed instead which adds one more indirection. This is the exact reason why unique_ptr is not as fast as a raw pointer and why clang has the trivial_abi extension. [2]. Chandler Carruth had a pretty good talk (imo) abou the existance of zero cost abstraction at cppcon19 [3]. [1] https://uclibc.org/docs/psABI-x86_64.pdf [2] https://quuxplusone.github.io/blog/2018/05/02/trivial-abi-101/ [3] https://www.youtube.com/watch?v=rHIkrotSwcc
olli
- Invisible reference, footnote? What these terms refer to?! - What's the relation between passing by value and having a well defined address?!
[1] The footnote is just a footnote in the document most likely added for clarification. Let's look at the example below, what assembly can we expect? struct NTD { ~NTD() {} }; extern void foo(NTD); int main() { foo({}); } compiling with -O3 generates the following assembly, as we can see the value passed to the function is not an object but rather an address (rsp), this address is an invisible reference to the object passed. main: # @main push rax mov rdi, rsp call foo(NTD) xor eax, eax pop rcx ret The above example is probably the most trivial one, it gets worse if NTD actually has some trivial members. [2] if you pass something in a register, you can't take the address of it since it's in the register.
MᏫᎻᎯᎷᎷᎬᎠ
{} is an address?!!
MᏫᎻᎯᎷᎷᎬᎠ
I would say it is just a temporary value with some conversion done since it's trivial and not explicit by default
olli
no, it's not an address but since the type is not trivial the ABI requires the temporary to have an address.
olli
correct, or rather you can't just pass the pointer in a register
MᏫᎻᎯᎷᎷᎬᎠ
I don't recall it has one except only when it's moved + There's a zero-abstraction, isn't?
olli
I don't recall it has one except only when it's moved + There's a zero-abstraction, isn't?
It does not hold the reference itself but rather the caller. For the rather simple code foo(std::make_unique<int>(3)); the assembly looks like call operator new(unsigned long) mov dword ptr [rax], 3 mov qword ptr [rsp + 8], rax lea rdi, [rsp + 8] call foo(...) foo again gets passed an addressed, not the address of the allocated memory but rather the unique_ptr object on the stack of the calling function.
MᏫᎻᎯᎷᎷᎬᎠ
I think the latest compilers optimized this
olli
I think the latest compilers optimized this
I was compiling with trunk of gcc and clang
olli
The thing is, compilers might be smart enough but they "need" to conform to the ABI spec as well so there's not a lot they can do.
MᏫᎻᎯᎷᎷᎬᎠ
thanks Olli for answering my a lot and annoying questions :)
olli
thanks Olli for answering my a lot and annoying questions :)
no worries :) (you might the find the talk linked above interesting, in case you have not seen it yet)
MᏫᎻᎯᎷᎷᎬᎠ
olli
this one? https://www.youtube.com/watch?v=rHIkrotSwcc
yes, assuming you don't mind reading assembly :)
MᏫᎻᎯᎷᎷᎬᎠ
yes, assuming you don't mind reading assembly :)
Lol I just measure how many lines there and make shallow judgments xD
klimi
No it's not
What is it then danya?
MᏫᎻᎯᎷᎷᎬᎠ
What is it then danya?
Yeah it's internally implemented as a pointer with a fixed size area
klimi
And type? Possibly... Not sure