updating std::vector<std::string>

Started by
6 comments, last by SmkViper 8 years, 4 months ago

so basically i am doing opengl text editor, text field is a std::vector<std::string> where each index is a line.

now what i want to know is, can i modify the content without overwriting the data like: (i mean since std::string is changeable, will change in some Strings, affest the whole vector that mean if lets say i add some string to it, will it be in Strings or in Strings[i+1], i dont know how to ask that, so maybe in other words: is it safe to update that or do i have to recreate whole std::vector<std::string>

(basically i want to add some text to the string itself)


std::vector<std::string> Strings;//divide string into two sections

AnsiString prefix = stddelete(Strings[memo_line], memo_pos, 100000);
AnsiString suffix = stddelete(Strings[memo_line], 0, memo_pos);

Strings[memo_line] = prefix + keys[i].key_char + suffix; <-- here

[spoiler]


inline AnsiString stddelete(AnsiString str, int pos, int len) //this is for std::string only because i will call only Pos()-1 from it
{
	AnsiString s = str;
	 s.erase(pos, len);
	 return s;
} 

[/spoiler]

Advertisement
Ahhhh... my eyes.

std::vector<std::string> strings;
 
strings[memo_line].insert(memo_pos, 1, keys[i].key_char);

Also, what's with mixing the std::string and AnsiString types, passing std::string by value, and mixing UpperCase with underscore_case?

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Also, what's with mixing the std::string and AnsiString types,

its a typedef of std::string for C++ builder compatibility

passing std::string by value, and mixing UpperCase with underscore_case?

i dont understand

either way can i safely append a string in that vector? because std::string can be any size so i am worried if the string lets say in line 3 be longer than was before, it could write the data into some other memory block which can be already stored for something else, thats why i ask is it safe or not?

either way can i safely append a string in that vector? because std::string can be any size so i am worried if the string lets say in line 3 be longer than was before, it could write the data into some other memory block which can be already stored for something else, thats why i ask is it safe or not?

std::vector and std::string store their data on the heap, not the stack, so it doesn't work like that. It works more like this:

[0] -> "hello, World!"
[1] -> "Second string"
.
.
.
[n] -> "Another string"
Each string allocates their own memory on the heap. They aren't stored contiguously within the vector.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

They aren't stored contiguously within the vector.

thats great, that really saved my day :P

i dont understand

I want to clarify this carefully. Your stddelete() function is extremely inefficient, because of how many times it causes the string to be copied.

inline AnsiString stddelete(AnsiString str, int pos, int len)
This function declares that the string is passed by value (i.e. on the stack), which causes the string to be copied when you call the function. You could avoid that by passing it by reference instead, as in const AnsiString &str.

AnsiString s = str;
This copies the string again. Since you passed the string into the function by value, we already have a local copy, and don't need to copy it again.

s.erase(pos, len);
Erasing characters from anywhere except the end of the string will cause all the following characters to be copied, so that the string is once again contiguous in memory.

return s;
The function also returns by value, so this will copy the string once again.

We're now at 4 string copies for this function, and your whole code snippet calls it twice, and then performs two string concatenations, for a total of 10 string copies. Versus one string copy for the solution using string.insert().

(the compiler should actually be smart enough to elide a number of the copies in your code snippet, but better we not rely on the compiler being smart)

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]


The function also returns by value, so this will copy the string once again.


(the compiler should actually be smart enough to elide a number of the copies in your code snippet, but better we not rely on the compiler being smart)

I'm not 100% sure, but almost certain that any halfway modern compiler will at least avoid the copy when returning the value. The C++-standard even defines that this special optimisation may as well alter executional behaviour (https://en.wikipedia.org/wiki/Return_value_optimization). Now its true that the compiler can actually do anything ranging from 2 copies to 1 move, from what I know and have read its very unlikely that a compiler won't make use of this optimization. For example, at least in MSVC you can verify this by returning a move-only data structure without a move:


std::unique_ptr<Object> void generateObject(void)
{
    auto pObject = sys::make_unique<MyObject>();

    return pObject; // can be returned without explicite move
}

Or is this due to another (optimization) rule?

Just wanted to bring this into discussion, since while its certainly good to know that return by value can invoke an additional copy, its worth mentioning that in the AFAIK likely case that this doesn't happen, it can make your life a little easier.

If you have a C++11 compatible compiler, and the type supports move semantics (which std::string does), then returning by value will not cause a copy, but will cause a move (not free, but also not as expensive as a copy). In some circumstances it won't even cause a move if the compiler can do RVO and just re-use the variable in the calling function.

Passing by value might cause a move, but only if you give it an r-value. Otherwise, giving it an l-value will force a copy.


void SomeFunction(std::string SomeValue);

SomeFunction(std::string("a value")); // will move - temporary passed in
SomeFunction(someVariable); // will copy
SomeFunction(std::move(someVariable)); // will move - someVariable is in a valid but unknown state (likely empty)
In general, passing by reference is still faster than passing by value, even with move semantics. However returning a local variable by value with a move-supported type is now generally preferred to passing in a value by reference that is modified by the function (ignoring other possible optimizations, like passing in a value with pre-allocated storage that can be re-used).

This topic is closed to new replies.

Advertisement