1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-09 13:22:24 +03:00

0029258: Foundation Classes - provide move constructors for string classes

New macro OCCT_NO_RVALUE_REFERENCE is introduced to disable methods using move semantics on obsolete compilers that do not support rvalue references.

TCollection_AsciiString, TCollection_ExtendedString, NCollection_UtfString - added method Swap(), move constructor, and move assignment operator.

Draw command QATestArrayMove is added to test for memory corruption if NCollection_Array1<> bound to local C buffer is returned from function by value.
This commit is contained in:
kgv
2017-10-15 16:08:01 +03:00
committed by bugmaster
parent 4ecf34cce7
commit 6286195cff
9 changed files with 209 additions and 22 deletions

View File

@@ -155,6 +155,7 @@ public:
// ---------- PUBLIC METHODS ------------
//! Empty constructor; should be used with caution.
//! @sa methods Resize() and Move().
NCollection_Array1()
: myLowerBound (1),
myUpperBound (0),
@@ -188,25 +189,36 @@ public:
Standard_OutOfMemory_Raise_if (!pBegin, "NCollection_Array1 : Allocation failed");
myData = pBegin - myLowerBound;
*this = theOther;
Assign (theOther);
}
#ifndef OCCT_NO_RVALUE_REFERENCE
//! Move constructor
#if(defined(_MSC_VER) && (_MSC_VER < 1600))
#else
NCollection_Array1 (NCollection_Array1&& theOther)
: myLowerBound (theOther.myLowerBound),
myUpperBound (theOther.myUpperBound),
myDeletable (theOther.myDeletable),
myData (theOther.myData)
{
theOther.myUpperBound = theOther.myLowerBound - 1;
theOther.myDeletable = false;
theOther.myData = NULL;
}
#endif
//! C array-based constructor
//! C array-based constructor.
//!
//! Makes this array to use the buffer pointed by theBegin
//! instead of allocating it dynamically.
//! Argument theBegin should be a reference to the first element
//! of the pre-allocated buffer (usually local C array buffer),
//! with size at least theUpper - theLower + 1 items.
//!
//! Warning: returning array object created using this constructor
//! from function by value will result in undefined behavior
//! if compiler performs return value optimization (this is likely
//! to be true for all modern compilers in release mode).
//! The same happens if array is copied using Move() function
//! or move constructor and target object's lifespan is longer
//! than that of the buffer.
NCollection_Array1 (const TheItemType& theBegin,
const Standard_Integer theLower,
const Standard_Integer theUpper) :
@@ -262,7 +274,9 @@ public:
Standard_Boolean IsAllocated (void) const
{ return myDeletable; }
//! Assignment
//! Copies data of theOther array to this.
//! This array should be pre-allocated and have the same length as theOther;
//! otherwise exception Standard_DimensionMismatch is thrown.
NCollection_Array1& Assign (const NCollection_Array1& theOther)
{
if (&theOther == this)
@@ -281,7 +295,10 @@ public:
return *this;
}
//! Move assignment
//! Move assignment.
//! This array will borrow all the data from theOther.
//! The moved object will keep pointer to the memory buffer and
//! range, but it will not free the buffer on destruction.
NCollection_Array1& Move (NCollection_Array1& theOther)
{
if (&theOther == this)
@@ -293,26 +310,25 @@ public:
{
delete[] &myData[myLowerBound];
}
myLowerBound = theOther.myLowerBound;
myUpperBound = theOther.myUpperBound;
myDeletable = theOther.myDeletable;
myData = theOther.myData;
theOther.myUpperBound = theOther.myLowerBound - 1;
theOther.myDeletable = Standard_False;
theOther.myData = NULL;
theOther.myDeletable = Standard_False;
return *this;
}
//! Assignment operator
//! Assignment operator; @sa Assign()
NCollection_Array1& operator= (const NCollection_Array1& theOther)
{
return Assign (theOther);
}
//! Move assignment operator.
#if(defined(_MSC_VER) && (_MSC_VER < 1600))
#else
#ifndef OCCT_NO_RVALUE_REFERENCE
//! Move assignment operator; @sa Move()
NCollection_Array1& operator= (NCollection_Array1&& theOther)
{
return Move (theOther);
@@ -424,7 +440,10 @@ public:
//! Destructor - releases the memory
~NCollection_Array1 (void)
{ if (myDeletable) delete [] &(myData[myLowerBound]); }
{
if (myDeletable)
delete [] &(myData[myLowerBound]);
}
protected:
// ---------- PROTECTED FIELDS -----------

View File

@@ -80,6 +80,11 @@ public:
//! @param theCopy string to copy.
NCollection_UtfString (const NCollection_UtfString& theCopy);
#ifndef OCCT_NO_RVALUE_REFERENCE
//! Move constructor
NCollection_UtfString (NCollection_UtfString&& theOther);
#endif
//! Copy constructor from UTF-8 string.
//! @param theCopyUtf8 UTF-8 string to copy
//! @param theLength optional length limit in Unicode symbols (NOT bytes!)
@@ -196,7 +201,18 @@ public:
public: //! @name assign operators
//! Copy from another string.
const NCollection_UtfString& operator= (const NCollection_UtfString& theOther);
const NCollection_UtfString& Assign (const NCollection_UtfString& theOther);
//! Exchange the data of two strings (without reallocating memory).
void Swap (NCollection_UtfString& theOther);
//! Copy from another string.
const NCollection_UtfString& operator= (const NCollection_UtfString& theOther) { return Assign (theOther); }
#ifndef OCCT_NO_RVALUE_REFERENCE
//! Move assignment operator.
NCollection_UtfString& operator= (NCollection_UtfString&& theOther) { Swap (theOther); return *this; }
#endif
//! Copy from UTF-8 NULL-terminated string.
const NCollection_UtfString& operator= (const char* theStringUtf8);

View File

@@ -90,6 +90,23 @@ NCollection_UtfString<Type>::NCollection_UtfString (const NCollection_UtfString&
strCopy ((Standard_Byte* )myString, (const Standard_Byte* )theCopy.myString, mySize);
}
#ifndef OCCT_NO_RVALUE_REFERENCE
// =======================================================================
// function : NCollection_UtfString
// purpose :
// =======================================================================
template<typename Type> inline
NCollection_UtfString<Type>::NCollection_UtfString (NCollection_UtfString&& theOther)
: myString(theOther.myString),
mySize (theOther.mySize),
myLength(theOther.myLength)
{
theOther.myString = NULL;
theOther.mySize = 0;
theOther.myLength = 0;
}
#endif
// =======================================================================
// function : NCollection_UtfString
// purpose :
@@ -159,11 +176,11 @@ NCollection_UtfString<Type>::~NCollection_UtfString()
}
// =======================================================================
// function : operator=
// function : Assign
// purpose :
// =======================================================================
template<typename Type> inline
const NCollection_UtfString<Type>& NCollection_UtfString<Type>::operator= (const NCollection_UtfString<Type>& theOther)
const NCollection_UtfString<Type>& NCollection_UtfString<Type>::Assign (const NCollection_UtfString<Type>& theOther)
{
if (this == &theOther)
{
@@ -178,6 +195,26 @@ const NCollection_UtfString<Type>& NCollection_UtfString<Type>::operator= (const
return (*this);
}
// =======================================================================
// function : Swap
// purpose :
// =======================================================================
template<typename Type> inline
void NCollection_UtfString<Type>::Swap (NCollection_UtfString<Type>& theOther)
{
// Note: we could use std::swap() here, but prefer to not
// have dependency on <algorithm> header at that level
Type* aString = myString;
const Standard_Integer aSize = mySize;
const Standard_Integer aLength = myLength;
myString = theOther.myString;
mySize = theOther.mySize;
myLength = theOther.myLength;
theOther.myString = aString;
theOther.mySize = aSize;
theOther.myLength = aLength;
}
#if !defined(__ANDROID__)
//! Auxiliary convertion tool.
class NCollection_UtfStringTool