How to pass std::string_view by value or by const reference - c++17

Usually string_view is used for function parameters like this:
void fval(std::string_view sv);
void fcref(std::string_view const &sv);
Which is better?
const reference is 8 bytes and string_view is usually twice that, e.g. 16 bytes.
However, if not inlined or optimized away, const reference might have two indirections - one for the ref, second for the pointer inside.
How STL doing it?

We usually pass string_views by value.
Examples from the C++20 draft:
Formatting
Time Zone Lookup

Related

Invalid type conversion while using ANSI c

I am facing this problem as when I am trying to build the code using ANSI C, as I was practicing writing in it and dealing with its rules, it tells me invalid type conversion and I don't know what to do.
this is the code line that makes the error, it is a pointer to function:
((CanIf_FuncTypeCanSpecial)(entry->CanIfUserRxIndication))(
entry->CanIfCanRxPduHrhRef->CanIfCanControllerHrhIdRef,
entry->CanIfCanRxPduId,
CanSduPtr,
CanDlc,
CanId);
and this is howentry->CanIfUserRxIndication is declared, as void *CanIfUserRxIndication;
and this is how CanIf_FuncTypeCanSpecial is declared, as
typedef void (*CanIf_FuncTypeCanSpecial)
(uint8 channel, PduIdType pduId, const uint8 *sduPtr, uint8 dlc, Can_IdType canId);
every parameter in the conversion type is the same type as the input parameters except the first one entry->CanIfCanRxPduHrhRef->CanIfCanControllerHrhIdRef it is from type enum not uint8.
You can find the code on GitHub.
and also the MISRA Rule is telling me this:
#1398-D (MISRA-C:2004 11.1/R) Conversions shall not be performed between a pointer to a function and any type other than an integral type
I tried to convert from enum to uint8 to make all of the parameters as what the type conversion CanIf_FuncTypeCanSpecial takes, but nothing happened.
If I understand correctly, you are trying to cast an existing function to match a function pointer declaration that has a differing argument type. You can cast the parameters and call such a function, but because function pointers themselves may be used anywhere in the program, at the places where they would be used the code would not know what to cast (which may result in a size difference) this is illegal.

zig structs, pointers, field access

I was trying to implement vector algebra with generic algorithms and ended up playing with iterators. I have found two examples of not obvious and unexpected behaviour:
if I have pointer p to a struct (instance) with field fi, I can access the field as simply as p.fi (rather than p.*.fi)
if I have a "member" function fun(this: *Self) (where Self = #This()) and an instance s of the struct, I can call the function as simply as s.fun() (rather than (&s).fun())
My questions are:
is it documented (or in any way mentioned) somewhere? I've looked through both language reference and guide from ziglearn.org and didn't find anything
what is it that we observe in these examples? syntactic sugar for two particular cases or are there more general rules from which such behavior can be deduced?
are there more examples of weird pointers' behaviour?
For 1 and 2, you are correct. In Zig the dot works for both struct values and struct pointers transparently. Similarly, namespaced functions also do the right thing when invoked.
The only other similar behavior that I can think of is [] syntax used on arrays. You can use both directly on an array value and an array pointer interchangeably. This is somewhat equivalent to how the dot operates on structs.
const std = #import("std");
pub fn main() !void {
const arr = [_]u8{1,2,3};
const foo = &arr;
std.debug.print("{}", .{arr[2]});
std.debug.print("{}", .{foo[2]});
}
AFAIK these are the only three instances of this behavior. In all other cases if something asks for a pointer you have to explicitly provide it. Even when you pass an array to a function that accepts a slice, you will have to take the array's pointer explicitly.
The authoritative source of information is the language reference but checking it quickly, it doesn't seem to have a dedicated paragraph. Maybe there's some example that I missed though.
https://ziglang.org/documentation/0.8.0/
I first learned this syntax by going through the ziglings course, which is linked to on ziglang.org.
in exercise 43 (https://github.com/ratfactor/ziglings/blob/main/exercises/043_pointers5.zig)
// Note that you don't need to dereference the "pv" pointer to access
// the struct's fields:
//
// YES: pv.x
// NO: pv.*.x
//
// We can write functions that take pointer arguments:
//
// fn foo(v: *Vertex) void {
// v.x += 2;
// v.y += 3;
// v.z += 7;
// }
//
// And pass references to them:
//
// foo(&v1);
The ziglings course goes quite in-depth on a few language topics, so it's definitely work checking out if you're interested.
With regards to other syntax: as the previous answer mentioned, you don't need to dereference array pointers. I'm not sure about anything else (I thought function pointers worked the same, but I just ran some tests and they do not.)

Memory usage of pass by value vs. pass by reference

For the past few days am trying to learn if pass by value and pass by reference impact the memory differently. Googling this query, people kept repeating themselves about a copy being created in terms of pass by value and how the original value is affected in terms pass by reference. But I was wondering if someone could zero in on the memory part.
This question actually depends heavily on the particular language as some allow you to be explicit and define when you want to pass a variable by value and when by reference and some do it always the same way for different types of variables.
A quite popular type of behavior is to use passing by value (by default) for simple times: like int, string, long, float, double, bool etc.
Let us show the memory impact on a theoretical language:
int $myVariable = 5;
at this moment you have created a one variable in memory which takes the size required to store an integer (let us say 32 bits).
Now you want to pass it to a function:
function someFunction(int parameter)
{
printOnScreen(parameter);
}
so your code would look like:
function someFunction(int $parameter)
{
printOnScreen($parameter);
}
int $myVariable = 5; //Position A
someFunction($myVariable); //Position B
...rest of the code //Position C
Since simple types are passed by value the value is copied in memory to another storage place - therefore:
during Position A you have memory occupied by ONE int (with value 5);
during Position B you have memory occupied by TWO ints (with values of 5) as your $myVariable was copied in memory
during Position C you have again memory occupied by ONE int (with value of 5) as the second one was already destroyed as it was needed only for the time of execution of the function
This has some other implications: modifications on a variable passed by value DO NOT affect the original variable - for example:
function someFunction(int $parameter)
{
$parameter = $parameter + 1;
printOnScreen($parameter);
}
int $myVariable = 5; //Position A
someFunction($myVariable); //Position B
printOnScreen($myVariable); //Position C
During position A you set value of 5 under variable $myVariable.
During position B you pass it BY VALUE to a function which adds 1 to your passed value. YET since it was a simple type, passed by value, it actually operates on a LOCAL variable, a COPY of your variable. Therefore position C will again write just 5 (your original variable as it was not modified).
Some languages allow you to be explicit and inform that you want to pass a reference and not the value itself using a special operator -for example &. So let us again follow the same example but with explicit info that we want a reference (in function's arguments
- note the &):
function someFunction(int &$parameter)
{
$parameter = $parameter + 1;
printOnScreen($parameter);
}
int $myVariable = 5; //Position A
someFunction($myVariable); //Position B
printOnScreen($myVariable); //Position C
This time operation and memory implications will be different.
During Position A an int is created (every variable is always consisted of two elements: place in memory and a pointer, an identifier which place is it. For ease of the process let us say that pointer is always one byte). So whenever you create a variable you actually create two things:
reserved place in memory for the VALUE (in this case 32 bits as it was an int)
pointer (8 bits [1 byte])
Now during position B, the function expects A POINTER to a memory place. Which means that it will locally, for itself create only a copy of the pointer (1 byte) and not copy the actual reserved place as the new pointer WILLL POINT to the same place as the original one. This means that during operation of the function you have:
TWO POINTERS to an int in memory
ONE place reserved for VALUE of the int
Both of those pointer POINT to the same VALUE
Which means that any modification of the value will affect both.
So looking at the same example position C will not print out also 6 as inside the function we have modified the value under the SAME POINTER as $myVariable.
For COMPLEX TYPES (objects) the default action in most programming environments is to pass the reference (pointer).
So for example - if you have a class:
class Person {
public string $name;
}
and create an instance of it and set a value:
$john = new Person();
$john->name = "John Malkovic";
and later pass it to a function:
function printName(Person $instanceOfPerson)
{
printOnScreen($instanceOfPerson);
}
in terms of memory it will again create only a new POINTER in memory (1 byte) which points to the same value. So having a code like this:
function printName(Person $instanceOfPerson)
{
printOnScreen($instanceOfPerson);
}
$john = new Person(); // position A
printName($john); // position B
...rest of the code // position C
during position A you have: 1 Person (which means 1 pointer [1 byte] to a place in memory which has size to store an object of class person)
during position B you have: 2 pointers [2 bytes] but STILL one place in memory to store an object of class person's value [instance]
during position C you have again situation from position A
I hope that this clarifies the topic for you - generally there is more to cover and what I have mentioned above is just a general explanation.
Pass-by-value and pass-by-reference are language semantics concepts; they don't imply anything about the implementation. Usually, languages that have pass-by-reference implement it by passing a pointer by value, and then when you read or write to the variable inside the function, the compiler translates it into reading or writing from a dereference of the pointer. So you can imagine, for example, if you have a function that takes a parameter by reference in C++:
struct Foo { int x; }
void bar(Foo &f) {
f.x = 42;
}
Foo a;
bar(a);
it is really syntactic sugar for something like:
struct Foo { int x; }
void bar(Foo *f_ptr) {
(*f_ptr).x = 42;
}
Foo a;
bar(&a);
And so passing by reference has the same cost as passing a pointer by value, which does involve a "copy", but it's the copy of a pointer, which is a few bytes, regardless of the size of the thing pointed to.
When you talk about pass-by-value doing a "copy", that doesn't really tell you much unless you know what exactly the variable or value passed represents in the language. For example, Java only has pass-by-value. But every type in Java is either a primitive type or a reference type, and the values of reference types are "reference", i.e. pointers to objects. So you can never have a value in Java (what a variable holds or what an expression evaluates to) which "is" an "object"; objects in Java can only be manipulated through these "references" (pointers to objects). So when you ask the cost of passing a object in Java, it's actually wrong because you cannot "pass" an object in Java; you can only pass references (pointers to objects), and the copy the happens for pass-by-value, is the copy of the pointer, which is a few bytes.
So the only case where you would actually copy a big structure when passing, is if you have a language where objects or structs are values directly (not behind a reference), and you do pass-by-reference of that object/struct type. So for example, in C++, you can have objects which are values directly, or you can have pointers to them, and you can pass them by value or by reference:
struct Foo { int x; }
void bar1(Foo f1) { } // pass Foo by value; this copies the entire size of Foo
void bar2(Foo *f2) { } // pass pointer by value; this copies the size of a pointer
void bar3(Foo &f3) { } // pass Foo by reference; this copies the size of a pointer
void bar4(Foo *&f4) { } // pass pointer by reference; this copies the size of a pointer
(Of course, each of those have different semantic meanings; for example, the last one allows the code inside the function to modify the pointer variable passed to point to somewhere else. But if you are concerned about the amount copied. Only the first one is different. In Java, effectively only the second one is possible.)

What will happen when malloc non-trivial type?

Only objects (including arrays) of trivial type may be created by a call to std::malloc.
I read it from http://en.cppreference.com/w/cpp/types/is_trivial, under the Note section.
So if I have a non-trivial type T, what will happen if I use std::malloc( sizeof(T) )?
std::malloc is just a "renaming" of old C (not C++) function malloc(3).
So if it succeeds, it malloc(sizeof(T)) returns a pointer to an uninitialized memory zone of the size needed by T
You need to call some constructor of T on that memory zone. You could use the placement new for that purpose, e.g:
void* p = std::malloc(sizeof(T));
if (!p) throw your_out_of_memory_exception();
T* ptr = new(p) T(32); /// placement new, with constructor called with 32
Actually many C++ implementations have their standard ::operator new doing something similar. (So new calls malloc !)

E2099 Overflow in conversion or arithmetic operation

I want to compare an int64 with a variable like this:
const GB=1073741824;
if DiskFile.Size< 1*GB then
It works with 1 but not with 3:
if DiskFile.Size< 3*GB then
This post (Strange Delphi integer multiplication behavior) explains why. I agree with that explanation. The result of 2*GB cannot fit in 'integer'. What I don't understand is why the compiler chooses integer instead the int64? As in the case of:
if DiskFile.Size< 3073741824 then <--------- almost 3GB
that works.
There is any way to write the last line of code in the 3*GB style (using constants) BUT without defining a new constant for 1GB, 2GB, 3GB, 4GB, etc ?
The first thing to be clear of here is that the integer overflow occurs in the compiler. The compiler has to evaluate your expression because it is a constant expression and they are evaluated by the compiler.
The documentation is a little sparse (and I am being kind here) on how the compiler treats your expression. We can infer, at least empirically, that the compiler attempts to perform 3*GB in a signed integer context. That is clear from the error message.
You need to force the compiler to evaluate the expression in an Int64 context. A cast will force that:
if DiskFile.Size< Int64(3)*GB then
....
Another option is to make the constant have type Int64:
const
GB = Int64(1073741824);
Although I think I'd write it like this:
const
KB = Int64(1024);
MB = 1024*KB;
GB = 1024*MB;
So long as GB is a 64 bit type then you can revert to:
if DiskFile.Size < 3*GB then
....
I'd like to elaborate on my second paragraph above. How can we tell that the compiler performs the arithmetic in 32 bit signed integer context? The following program suggests that this is so:
{$APPTYPE CONSOLE}
const
C1 = 715827882; // MaxInt div 3
C2 = C1+1;
begin
Writeln(3*C1);
Writeln(3*C2);
Readln;
end.
The first expression, 3*C1 compiles, the second fails with E2099. The first expression does not overflow a signed 32 bit integer, the second does.
When looking at the documentation, it is unclear whether the true constant 1073741824 should be of type Integer or Cardinal. The compiler could choose either. It seems that the compiler, when presented with a choice between signed and unsigned types, chooses signed types.
But then one might imagine that the following program would behave in the same way, but with Smallint and Word taking the place of Integer and Cardinal:
{$APPTYPE CONSOLE}
const
C1 = 10922; // high(Smallint) div 3
C2 = C1+1;
begin
Writeln(3*C1);
Writeln(3*C2);
Readln;
end.
But no, this program compiles. So, at this point I am giving up on the documentation which appears to bear little relationship to the actual behaviour of the compiler.
My best guess is that a integral true constant is handled as follows:
If it is within the range of Integer, it is of type Integer.
Otherwise, if it is within the range of Cardinal, it is of type Cardinal.
Otherwise, if it is within the range of Int64, it is of type Int64.
Otherwise, if it is within the range of UInt64, it is of type UInt64.
Otherwise it is a compiler error.
Of course, all of this assumes that the compilers rules for evaluating constant expressions follow the same rules as the rest of the language. I'm not certain that is the case.

Resources