Replace a string from a vector of string C++ - c++

I have a vector of string constructed using:
vector<string> names;
names.push_back("Gates");
names.push_back("Jones");
names.push_back("Smith");
names.push_back("Gates");
I want to replace "Gates" with "Bill", for every occurrence of "Gates".
For this the easiest solution I know is to use the replace function from algorithm and use it as:
replace(names.begin(), names.end(), "Gates", "Bill");
But I am getting following error:
parameter type mismatch:incompatible types 'const char (&)[6]' and 'const char[5]'.
I can solve it using implicit type casting like this:
replace(names.begin(), names.end(), "Gates", (const char (&)[6]) "Bill");
Can anyone explain what this error is, and better way to solve it or better way to do it. Or why do we need this type casting.

The old/new value parameters in std::replace share the same type.
For example, the function might look like:
template<class ForwardIt, class T>
void replace(ForwardIt first, ForwardIt last, const T& old_value, const T& new_value);
Stolen from here, not that it's that significant.
"gates" is a const char[6] but bill is a const char[5], which is why you get the error about being unable to convert it.
You could either wrap each string literal in std::string() or just use the unary + operator to decay each literal to a const char*.
replace(names.begin(), names.end(), +"Gates", +"Bill"); //shorter
replace(names.begin(), names.end(), std::string("Gates"), std::string("Bill")); //clearer
I'm pretty sure ((const char (&)[6]) "Bill") violates strict aliasing, so I'd avoid casting between array types like that.

I would suggest (assuming some using std;)
replace(names.begin(), names.end(), string{"Gates"}, string{"Bill"});
since the type of "Gates" is char[6] (decayed to char*) and you want to replace std::string-s (not char* !!).

Related

How to convert string to const unsigned char* without using reinterpret_cast (modern approach)

I have variable input type const std::string&:
const std::string& input
Now I need to convert this to const unsigned char* because this is the input of the function.
Unitl now I have correct code for converting:
reinterpret_cast<const unsigned char*>(input.c_str())
This works well, but in clang I got a warning:
do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]
What is the correct way to change a string or const char* to const unsigned char*?
What is the correct way to change a string or const char* to const unsigned char*?
The correct way is to use reinterpret_cast.
If you want to avoid reinterpret_cast, then you must avoid the pointer conversion entirely, which is only possible by solving the XY-problem. Some options:
You could use std::basic_string<unsigned char> in the first place.
If you only need an iterator to unsigned char and not necessarily a pointer, then you could use std::ranges::views::transform which uses static cast for each element.
You could change the function that expects unsigned char* to accept char* instead.
If you cannot change the type of input and do need a unsigned char* and you still must avoid reinterpret cast, then you could create the std::basic_string<unsigned char> from the input using the transform view. But this has potential overhead, so consider whether avoiding reinterpret_cast is worth it.
Edit
Apparently type punning with an union is UB so definitely don't do this.
(Keeping the answer for posterity though!)
To strictly answer your question, there's this way:
void foo(const unsigned char* str) {
std::cout << str << std::endl;
}
int main()
{
std::string word = "test";
//foo(word.data()); fails
union { const char* ccptr; const unsigned char* cucptr; } uword;
uword.ccptr = word.data();
foo(uword.cucptr);
}
Is this any better than a reinterpret_cast? Probably not.

Is there a way to use operator+ to concatenate std::strings in c++? [duplicate]

This question already has answers here:
What is the difference between these two cases of adding a string?
(5 answers)
Closed 7 years ago.
I have a function like this
void foo (const char* myString){
...
}
and I want to use it like this
std::string tail = "something";
foo("my" + "string" + tail);
But I just can't find an easy way. For sure I can make the string somewhere else and pass it to foo(). But I prefer to find a way to do it inline, because foo() is called several times in the code, I don't want to make a string for each time. I tried
foo(std::string ("my" + "string" + tail).c_str())
but you can guess that it doesn't work.
"my"and "string" are C style string literals, which have the odd rule that they will be concatenated if they are written without a +.
So "my" "string" + tail will work, and produce a std::string. However, it will still not be the correct type for your function, unless you use .c_str() on the result.
"my" and "string" are C-style strings. Their types are const char *, you cannot use operator + for these operands. But you can use this operator is any of the operands is string.
So the most elegant way for you it to add parenthesis:
foo(("my" + ("string" + tail)).c_str());
You will also have to change function foo to
void foo (const char* myString)
Just make sure "my" is a std::string, then you can use the std::string::operator+ operator on it. Later you use .c_str() on the resulting std::string.
Then, if you can change foo, the best is to make it accept const char*:
void foo (const char* myString)
{
...
}
std::string tail = "something";
foo( (std::string("my") + "string" + tail).c_str() );
If you can't change foo, then you'll have to do a cast because c_str() returns a const char* and foo wants a char*:
void foo (char* myString)
{
...
}
std::string tail = "something";
foo( const_cast<char*>( (std::string("my") + "string" + tail).c_str() ) );
Your function accepts a modifiable array (not anymore, OP changed that in an edit) of char and std::string is not an array of char, but some unrelated object (that provides read-access to its internal char buffer, but that does not make it some kind of pretty array).
Additionally, using .c_str()-pointers into destroyed string objects is a common bug. Even if your function was to accept a const char* instead, you need to be aware that the pointer passed into it would only be valid until the end of the full expression the temporary std::string object was created in. This might or might not be what you want here, but is something you really need to watch out for. As I said, people get it wrong quite often.
So std::string probably (in the new const char* setting, it might) is not the right tool for this job as it is described right now.
The best solution would be to make the argument of foo() an std::string (of some reference variant, depending on what it is doing). Then you can concatenate the inputs with + as long as one of the first summands already is an std::string.
If this should not be possible, copy the characters into an std::vector<char> which actually is the C++ way to get a char array (again, unlike string).
The code foo("my" + "string" + tail); does not work for two reasons. First is order of operators. The code tries to execute "my" + "string", and since both of those are string literals, code fails. (you can not add up two string literals). The first issue is that if you magically make "my" + "string" working, code will concatenate it with tail, produce valid std::string, but fail to pass it to foo().
How to fix the issue?
Change foo() signature. make it foo(const char* ) if you have to use char*, or, better, replace it with foo(const std::string&).
Use following to concatenate: foo(std::string("my") + "string" + tail) if you followed my advice and made foo accepting const std::string&, or foo((std::string("my") + "string" + tail).c_str()) if you did not.
On a side note, since both "my" and "string" are known at compile time, it's better to have simple foo("mystring" + tail) - easier to read, better performance.

C++: concatenate an enum to a std::string

So I'm trying to concatenate an enum to an std::string. For this I wrote the following code.
typedef enum { NODATATYPE = -1,
DATATYPEINT,
DATATYPEVARCHAR
} DATATYPE;
inline std::string operator+(std::string str, const DATATYPE dt){
static std::map<DATATYPE, std::string> map;
if (map.size() == 0){
#define INSERT_ELEMENT(e) map[e] = #e
INSERT_ELEMENT(NODATATYPE);
INSERT_ELEMENT(DATATYPEINT);
INSERT_ELEMENT(DATATYPEVARCHAR);
#undef INSERT_ELEMENT
}
return str + map[dt];
}
and
DATATYPE dt1 = DATATYPEINT;
std::string msg = "illegal type for operation" + dt1;
I'm getting the following warning compiling this code.
warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: std::string msg = "illegal type for operation" + dt1; absyn.cpp:642:55: note: candidate 1: operator+(const char*, long int)
In file included from file.cpp:4:0: file.h:18:20: note: candidate 2: std::string operator+(std::string, DATATYPE) inline std::string operator+(std::string str, const DATATYPE dt){
What does this warning exactly mean, and how to solve it?
What you pass to the operator is a const char* (to a string literal) and a DATATYPE. Since there is no overload operator+(const char*, DATATYPE), the compiler looks for overloads where the parameters can be implicitly converted. The candidates are in the warning:
operator+(const char*, long int)
operator+(std::string, DATATYPE)
The first parameter can be converted from const char* to std::string or the second parameter can be converted from DATATYPE to long int. So the first overload "wins" the overload resolution on the basis of first parameter and the second overload "wins" on the basis of the second argument. Since there is no overload that "wins" the resolution on the basis of both arguments, they are ambiguous.
The compiler warns you because it suspects that it may have chosen different overload than what you meant to call. If you compile with -pedantic on gcc you'll get error: ambiguous overload for... instead of just a warning.
The solution is to disambiguate the call by passing parameters of types that match exactly. A simple way would be:
std::string msg = std::string("illegal type for operation") + dt1;
or nicer in c++14
std::string msg = "illegal type for operation"s + dt1;

Converting string to const* char

I have two string declarations:
killerName
victimName
I need to convert these two string values to const* char.
Example of how I use my method:
if (killer.IsRealPlayer) {
killerName = killer.GetName(); -- need to convert to const* char
victimName = victim.GetName(); -- need to convert to const* char
Notice(killerName + "has slain:" + victimName, killer.GetMapIndex(), false);
}
Some error I receive:
Error 111 error C2664: 'Notice' : cannot convert parameter 1 from 'std::basic_string<_Elem,_Traits,_Ax>' to 'const char */
It seems that function Notice have the first parameter of type const char * However the expression passed to it as the first argument
killerName + "has slain:" + victimName
has type std::string
Simply call the function the following way
Notice( ( killerName + "has slain:" + victimName ).c_str(), killer.GetMapIndex(), false);
Notice(string(killerName + "has slain:" + victimName).c_str(), killer.GetMapIndex(), false);
std::string::c_str() gives the const char* to the buffer. I think that's what you want.
See: http://www.cplusplus.com/reference/string/string/c_str/
As others already wrote, the result of killerName + "has slain:" + victimName is of type std::string. So, if your Notice() function expects a const char* as first parameter, you must convert from std::string to const char*, and since there is no implicit conversion defined for std::string, you must call the std::string::c_str() method:
Notice((killerName + "has slain:" + victimName).c_str(), killer.GetMapIndex(), false);
However, I'd like to ask: why do you have Notice() expecting a const char* as first parameter?
Would it be better to just use const std::string&? In general, in modern C++ code, you may want to use string classes like std::string instead of raw char* pointers.
(Another option would be to have two overloads of Notice(): one expecting a const std::string& as first parameter, and the other one expecting a const char*, if for some reason the const char* version does make sense in your particular context; this double overload pattern is used e.g. in the std::fstream constructor.)

Invalid assignment to unsigned char C++

I wrote the following but for some reason calling InstructionVal(b) is invalid.
intellisense is spitting out:
Only () is allowed for initializer member NPPInstructionDef::InstructionVal
here is the offending code:
//Single Instruction Definition for Instruction Dictionary
typedef struct NPPInstructionDef
{
const char* InstructionName;
const unsigned char* InstructionVal[];
NPPInstructionDef(const char* a, const unsigned char* b[]): InstructionName(a), InstructionVal()
{
}
}NPPInstruction;
Any Ideas? Thanks.
First, I'm assuming your initialization is InstructionVal(
b ), rather than the InstructionVal() which you've written.
But even then, what you've written shouldn't compile.
This is the usual problem, due to the fact that C style arrays
are broken, and shouldn't be used. Your definition:
unsigned char const* InstructionVal[];
defines an array of unknown length (thus, illegal in a class
defintion) of unsigned char*. There's no way to initialize
this in an initialization list, except by () (value
initialization).
What you want is:
std::vector <unsigned char*> InstructionVal;
, and the constructor should be:
NPPInstructionDef( std::string const& a,
std::vector <unsigned char> const& b );
, or perhaps more likely:
template <typedef Iterator>
NPPInstructionDef( std::string const& a,
Iterator begin,
Iterator end )
: InstructionName( a )
, InstructionDef( begin, end )
{
}
(This supposes, of course, that InstructionName is
std::string, instead of char const*. Which will avoid any
issues of lifetime of the string, for example, and allow easy comparison, etc.)