Gooly
Gooly

Reputation: 79

Error when initializing a vector array of strings

I am trying to initialize a vector of strings by first initializing it in an array of char* and convert them into a vector. However the following code doesn't work, the vector ended up having three of the same first string and the forth, fifth, and sixth string.

string hand_lr_ = "left";
const char* x_joint_names_char[] = {("r2/"+hand_lr_+"_arm/wrist/yaw").c_str(),("r2/"+hand_lr_+"_arm/wrist/pitch").c_str(),("r2/"+hand_lr_+"_arm/hand/index/distal").c_str(),("r2/"+hand_lr_+"_arm/hand/ringlittle/ringMedial").c_str(),("r2/"+hand_lr_+"_arm/hand/ringlittle/ringDistal").c_str(),("r2/"+hand_lr_+"_arm/hand/ringlittle/ring").c_str() };

std::vector<std::string> x_joint_names(x_joint_names_char, x_joint_names_char + sizeof(x_joint_names_char)/sizeof(x_joint_names_char[0]));

for (int i =0; i < sizeof(x_joint_names_char)/sizeof(x_joint_names_char[0]) ;i++) {
  cout << x_joint_names[i] << endl;
  for (int j = 0; j < strlen(x_joint_names_char[i]); j++)
  {
    cout << x_joint_names_char[i][j];
  }
  cout << endl;
}

The code above outputs the following. Where a weird character appears.

r2/left_arm/wrist/yaw
8�{
r2/left_arm/wrist/yaw
r2/left_arm/wrist/yaw
r2/left_arm/wrist/yaw
r2/left_arm/wrist/yaw
r2/left_arm/hand/ringlittle/ringMedial
r2/left_arm/hand/ringlittle/ringMedial
r2/left_arm/hand/ringlittle/ringDistal
r2/left_arm/hand/ringlittle/ringDistal
r2/left_arm/hand/ringlittle/ring
r2/left_arm/hand/ringlittle/ring

The code works correctly if there are only five strings. It also appears normal if I don't assign the array to a vector. All the contents in x_joint_names_char are correct before assigning to a vector. Any idea what is the cause?

The initialization code is based on this post: Initialize a vector array of strings

Edit: Moving the hand_lr into the string like the following also works.

const char* x_joint_names_char[] = {("r2/left_arm/wrist/yaw"),("r2/left_arm/wrist/pitch"),("r2/left_arm/hand/index/distal"),("r2/left_arm/hand/ringlittle/ringMedial"),("r2/left_arm/hand/ringlittle/ringDistal"),("r2/left_arm/hand/ringlittle/ring") };

Upvotes: 1

Views: 79

Answers (1)

M.M
M.M

Reputation: 141554

The line initializing x_joint_names_char creates a pile of dangling pointers.

The expression ("r2/"+hand_lr_+"_arm/wrist/yaw") denotes a temporary string (since it has no name and wasn't dynamically allocated). The c_str() function produces a pointer to the temporary string, but then the temporary strings on that line are all destroyed when that line completes.

The use of char * in the linked thread is a micro-optimization that can only be used when the initializers are C-style string literals.

Since C++11 you can write:

std::vector<std::string> x_joint_names = {
    "r2/"+hand_lr_+"_arm/wrist/yaw",
    "r2/"+hand_lr_+"_arm/wrist/pitch",
    "r2/"+hand_lr_+"_arm/hand/index/distal"
};

for example. If you are forced to use an old compiler then make your preliminary array be an array of string, not an array of const char *. Or push_back each string into the vector and do away with the array.

Upvotes: 4

Related Questions