From 065df59a8c5dbe781e0a6f20cea726fc621bd9b2 Mon Sep 17 00:00:00 2001 From: abarton Date: Fri, 29 May 2026 21:28:40 +0100 Subject: [PATCH] Reduce memory allocations in the C++ interfaces --- c++/src/H5Attribute.cpp | 52 ++++++++++++++++++------------------ c++/src/H5DataSet.cpp | 14 +++------- c++/src/H5EnumType.cpp | 17 ++++++------ c++/src/H5Location.cpp | 58 ++++++++++++++--------------------------- c++/src/H5Object.cpp | 34 ++++++++++-------------- c++/src/H5PropList.cpp | 17 ++++++------ 6 files changed, 83 insertions(+), 109 deletions(-) diff --git a/c++/src/H5Attribute.cpp b/c++/src/H5Attribute.cpp index 5324e7da2a74..d40952b1d3bd 100644 --- a/c++/src/H5Attribute.cpp +++ b/c++/src/H5Attribute.cpp @@ -317,17 +317,14 @@ Attribute::getName() const // (unfortunate in/out type sign mismatch) size_t actual_name_size = static_cast(name_size) + 1; - // Create buffer for C string - char *name_C = new char[actual_name_size](); + // Create space for C string + attr_name.resize(actual_name_size); - // Use overloaded function - name_size = getName(name_C, actual_name_size); - - // Convert the C attribute name to return - attr_name = name_C; + // Use overloaded function, write directly into internal buffer + name_size = getName(&attr_name[0], actual_name_size); - // Clean up resource - delete[] name_C; + // Resize back to the actual length (excluding NUL) + attr_name.resize(name_size); } // Return attribute's name @@ -385,17 +382,19 @@ Attribute::getName(H5std_string &attr_name, size_t len) const } // If length is provided, get that number of characters in name else { - // Create buffer for C string - char *name_C = new char[len + 1](); + // Resize string to accommodate the requested length and terminal ASCII NUL + attr_name.resize(len + 1); // Use overloaded function - name_size = getName(name_C, len + 1); - - // Convert the C attribute name to return - attr_name = name_C; - - // Clean up resource - delete[] name_C; + name_size = getName(&attr_name[0], len + 1); + + // Truncate at the first null character to handle truncation/short buffers correctly + size_t null_pos = attr_name.find('\0'); + if (null_pos != H5std_string::npos) { + attr_name.resize(null_pos); + } else { + attr_name.resize(name_size); + } } // Otherwise, keep attr_name intact @@ -498,16 +497,19 @@ Attribute::p_read_fixed_len(const DataType &mem_type, H5std_string &strg) const // If there is data, allocate buffer and read it. if (attr_size > 0) { - char *strg_C = new char[attr_size + 1]; - herr_t ret_value = H5Aread(id, mem_type.getId(), strg_C); + // Resize the string to the attribute's size and read directly into it + strg.resize(attr_size+1); + herr_t ret_value = H5Aread(id, mem_type.getId(), &strg[0]); if (ret_value < 0) { - delete[] strg_C; // de-allocate for fixed-len string throw AttributeIException("Attribute::read", "H5Aread failed"); } - // Get string from the C char* and release resource allocated locally - strg_C[attr_size] = '\0'; - strg = strg_C; - delete[] strg_C; + // Replicate original C-string truncation (stops at first NUL character) + size_t null_pos = strg.find('\0'); + if (null_pos != H5std_string::npos) { + strg.resize(null_pos); + }else{ + strg.resize(attr_size); + } } } diff --git a/c++/src/H5DataSet.cpp b/c++/src/H5DataSet.cpp index d4839bb1e2d8..2f253dd15d8d 100644 --- a/c++/src/H5DataSet.cpp +++ b/c++/src/H5DataSet.cpp @@ -718,19 +718,13 @@ DataSet::p_read_fixed_len(const hid_t mem_type_id, const hid_t mem_space_id, con // If there is data, allocate buffer and read it. if (data_size > 0) { - // Create buffer for C string - char *strg_C = new char[data_size + 1](); - - herr_t ret_value = H5Dread(id, mem_type_id, mem_space_id, file_space_id, xfer_plist_id, strg_C); - + // Resize the string to the dataset's size and read directly into it + strg.resize(data_size+1); + herr_t ret_value = H5Dread(id, mem_type_id, mem_space_id, file_space_id, xfer_plist_id, &strg[0]); if (ret_value < 0) { - delete[] strg_C; // de-allocate for fixed-len string throw DataSetIException("DataSet::read", "H5Dread failed for fixed length string"); } - - // Get string from the C char* and release resource allocated locally - strg = H5std_string(strg_C, data_size); - delete[] strg_C; + strg.resize(data_size); } } diff --git a/c++/src/H5EnumType.cpp b/c++/src/H5EnumType.cpp index 978d22d7d86c..323bf7204847 100644 --- a/c++/src/H5EnumType.cpp +++ b/c++/src/H5EnumType.cpp @@ -205,19 +205,20 @@ EnumType::insert(const H5std_string &name, void *value) const H5std_string EnumType::nameOf(void *value, size_t size) const { - char *name_C = new char[size + 1](); // temporary C-string for C API - - // Calls C routine H5Tenum_nameof to get the name of the specified enum type - herr_t ret_value = H5Tenum_nameof(id, value, name_C, size); + H5std_string name; + name.resize(size+1); + // Calls C routine H5Tenum_nameof to get the name of the specified enum type directly into the string buffer + herr_t ret_value = H5Tenum_nameof(id, value, &name[0], size + 1); // If H5Tenum_nameof returns a negative value, raise an exception, if (ret_value < 0) { - delete[] name_C; throw DataTypeIException("EnumType::nameOf", "H5Tenum_nameof failed"); } - // otherwise, create the string to hold the datatype name and return it - H5std_string name(name_C); - delete[] name_C; + // Truncate at the first null character to account for the C API's null-termination + size_t null_pos = name.find('\0'); + if (null_pos != H5std_string::npos) { + name.resize(null_pos); + } return (name); } diff --git a/c++/src/H5Location.cpp b/c++/src/H5Location.cpp index a179adac4fc1..32d91180df5e 100644 --- a/c++/src/H5Location.cpp +++ b/c++/src/H5Location.cpp @@ -300,21 +300,13 @@ H5Location::getComment(const char *name, size_t buf_size) const if (tmp_len == 0) tmp_len = static_cast(comment_len); - // Temporary buffer for char* comment - char *comment_C = new char[tmp_len + 1](); - - // Used overloaded function - ssize_t temp_len = getComment(name, tmp_len + 1, comment_C); + comment.resize(tmp_len + 1); + ssize_t temp_len = getComment(name, tmp_len + 1, &comment[0]); if (temp_len < 0) { - delete[] comment_C; throw LocationException("H5Location::getComment", "H5Oget_comment_by_name failed"); } - // Convert the C comment to return - comment = comment_C; - - // Clean up resource - delete[] comment_C; + comment.resize(temp_len); } // Return the string comment @@ -1653,17 +1645,17 @@ H5Location::getLinkval(const char *name, size_t size) const // if link has value, retrieve the value, otherwise, return null string if (val_size > 0) { - // Create buffer for C string - value_C = new char[val_size + 1](); - - ret_value = H5Lget_val(getId(), name, value_C, val_size, H5P_DEFAULT); + value.resize(val_size + 1); + ret_value = H5Lget_val(getId(), name, &value[0], val_size, H5P_DEFAULT); if (ret_value < 0) { - delete[] value_C; throwException("getLinkval", "H5Lget_val failed"); } - value = H5std_string(value_C); - delete[] value_C; + // Truncate at the first null character to get the size correct + size_t null_pos = value.find('\0'); + if (null_pos != H5std_string::npos) { + value.resize(null_pos); + } } return (value); } @@ -1823,20 +1815,16 @@ H5Location::getObjnameByIdx(hsize_t idx) const // (unfortunate in/out type sign mismatch) size_t actual_name_len = static_cast(name_len) + 1; - // Create buffer for C string - char *name_C = new char[actual_name_len](); - - name_len = H5Lget_name_by_idx(getId(), ".", H5_INDEX_NAME, H5_ITER_INC, idx, name_C, actual_name_len, - H5P_DEFAULT); + H5std_string name; + name.resize(actual_name_len); + name_len = H5Lget_name_by_idx(getId(), ".", H5_INDEX_NAME, H5_ITER_INC, idx, &name[0], actual_name_len, + H5P_DEFAULT); if (name_len < 0) { - delete[] name_C; throwException("getObjnameByIdx", "H5Lget_name_by_idx failed"); } - - // clean up and return the string - H5std_string name = H5std_string(name_C); - delete[] name_C; + // Correct size + name.resize(name_len); return (name); } @@ -1876,19 +1864,13 @@ H5Location::getObjnameByIdx(hsize_t idx, char *name, size_t size) const ssize_t H5Location::getObjnameByIdx(hsize_t idx, H5std_string &name, size_t size) const { - // Create buffer for C string - char *name_C = new char[size + 1](); - - // call overloaded function to get the name - ssize_t name_len = getObjnameByIdx(idx, name_C, size + 1); + name.resize(size + 1); + ssize_t name_len = getObjnameByIdx(idx, &name[0], size + 1); if (name_len < 0) { - delete[] name_C; throwException("getObjnameByIdx", "H5Lget_name_by_idx failed"); } - - // clean up and return the string - name = H5std_string(name_C); - delete[] name_C; + // Correct to final size + name.resize(name_len); return (name_len); } diff --git a/c++/src/H5Object.cpp b/c++/src/H5Object.cpp index 8d15f88dfc40..8ecd12ae731b 100644 --- a/c++/src/H5Object.cpp +++ b/c++/src/H5Object.cpp @@ -483,17 +483,14 @@ H5Object::getObjName() const // (unfortunate in/out type sign mismatch) size_t actual_name_size = static_cast(name_size) + 1; - // Create buffer for C string - char *name_C = new char[actual_name_size](); - - // Use overloaded function - name_size = getObjName(name_C, actual_name_size); - - // Convert the C object name to return - obj_name = name_C; - - // Clean up resource - delete[] name_C; + // Resize string to accommodate the name and terminal ASCII NUL + obj_name.resize(actual_name_size); + + // Write directly into the string's contiguous buffer + name_size = getObjName(&obj_name[0], actual_name_size); + + // Resize back to the actual length (excluding NUL) + obj_name.resize(name_size); } // Return object's name @@ -524,17 +521,14 @@ H5Object::getObjName(H5std_string &obj_name, size_t len) const } // If length is provided, get that number of characters in name else { - // Create buffer for C string - char *name_C = new char[len + 1](); - - // Use overloaded function - name_size = getObjName(name_C, len + 1); + // Resize string to accommodate the requested length and terminal ASCII NUL + obj_name.resize(len + 1); - // Convert the C object name to return - obj_name = name_C; + // Write directly into the string's contiguous buffer + name_size = getObjName(&obj_name[0], len + 1); - // Clean up resource - delete[] name_C; + // Resize back to the actual length + obj_name.resize(name_size); } // Otherwise, keep obj_name intact diff --git a/c++/src/H5PropList.cpp b/c++/src/H5PropList.cpp index 2c13b25205c5..fa989e104ff5 100644 --- a/c++/src/H5PropList.cpp +++ b/c++/src/H5PropList.cpp @@ -434,20 +434,21 @@ PropList::getProperty(const char *name) const // Get property size first size_t size = getPropSize(name); - // Allocate buffer then get the property - char *prop_strg_C = new char[size + 1](); + H5std_string prop_strg; + prop_strg.resize(size+1); - herr_t ret_value = H5Pget(id, name, prop_strg_C); // call C API + // Get the property directly into the string's buffer + herr_t ret_value = H5Pget(id, name, &prop_strg[0]); // call C API\ // Throw exception if H5Pget returns failure if (ret_value < 0) { - delete[] prop_strg_C; throw PropListIException(inMemFunc("getProperty"), "H5Pget failed"); } - - // Return property value as a string after deleting temp C-string - H5std_string prop_strg(prop_strg_C); - delete[] prop_strg_C; + // Truncate at the first null character to account for the C API's null-termination + size_t null_pos = prop_strg.find('\0'); + if (null_pos != H5std_string::npos) { + prop_strg.resize(null_pos); + } return (prop_strg); } //--------------------------------------------------------------------------