• Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers
  • Advertising & Talent Reach devs & technologists worldwide about your product, service or employer brand
  • OverflowAI GenAI features for Teams
  • OverflowAPI Train & fine-tune LLMs
  • Labs The future of collective knowledge sharing
  • About the company Visit the blog

Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Get early access and see previews of new features.

Does std::string::assign takes "ownership" of the string?

I have some gaps in the understanding of string::assign method. Consider the following code:

Does s.assign allocate a new buffer and copy the string into it or it assumes ownership of the pointer; i.e. doesn't allocate new memory and uses directly my address. If it copies, then what is the difference between assign and operator= ? If it doesn't copy, then does it free the memory or it is my responsibility?

FireAphis's user avatar

  • 1 There is absolutely no way to make a std::string take ownership of a pointer you have, period :( –  Mooing Duck Commented Apr 4, 2014 at 23:30

3 Answers 3

Does s.assign allocate a new buffer and copy the string into it or it assumes ownership of the pointer;

The STL string method assign will copy the character array into the string. If the already allocated buffer inside the string is insufficient it will reallocate the memory internally. The STL string will not take ownership of the original array.

If it copies, then what is the difference between assign and operator=?

Both ought to act in the same way, but there are a number of overloads to the STL assign method which give you more control over what happens. Take a look at this page for more information.

UPDATE: The MSDN has a number of examples of the various assign overloads.

If it doesn't copy, then does it free the memory or it is my responsibility?

No, the original pointer to the character array is still your responsibility.

Konrad's user avatar

It copies. The difference between assign and operator= is that you can specify the number of characters to be copied including null characters . The operator= just copies the c-string up to the first null byte.

A. Levy's user avatar

As far as I can remember, it is up to the implementation of your compiler. Some may use copy-on-write optimizations and therefore create no copy until you modify the value. However, most implementations will just copy the string.

But, all implementations will take care of the cleanup - so no need for you to manually free the strings memory (that's what string objects are all about). Of course you have to free your string objects, if created on the heap (or use a smartpointer) ;)

Assign and operator= may be implemented in terms of each other as they do the same thing - depending on which version of assign is called (for all overloads see cpp reference ).

fmuecke's user avatar

  • 2 Copy-on-write can only be used hen assigning one string to another - it can't be used when assigning a char *. –  anon Commented Jul 12, 2010 at 15:18

Your Answer

Reminder: Answers generated by artificial intelligence tools are not allowed on Stack Overflow. Learn more

Sign up or log in

Post as a guest.

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy .

Not the answer you're looking for? Browse other questions tagged c++ string or ask your own question .

  • The Overflow Blog
  • Where does Postgres fit in a world of GenAI and vector databases?
  • Featured on Meta
  • We've made changes to our Terms of Service & Privacy Policy - July 2024
  • Bringing clarity to status tag usage on meta sites
  • Feedback requested: How do you use tag hover descriptions for curating and do...
  • What does a new user need in a homepage experience on Stack Overflow?
  • Staging Ground Reviewer Motivation

Hot Network Questions

  • What is the name of the book about a boy dressed in layers of clothes who is actually a mouse?
  • Is there a one-liner command or tool to create a virtual input device from default output on pipewire?
  • What are the risks of a compromised top tube and of attempts to repair it?
  • Is there any video of an air-to-air missile shooting down an aircraft?
  • How to allocate memory in NASM without C functions (x64)?
  • Where did Geordi's eyes go?
  • How could Bangladesh protect itself from Indian dams and barrages?
  • Can light become a satellite of a black hole?
  • My colleagues and I are travelling to UK as delegates in an event and the company is paying for all our travel expenses. what documents are required
  • Using "no" at the end of a statement instead of "isn't it"?
  • Can a TL431 be configured to output a negative reference voltage?
  • High CPU usage by process with obfuscated name on Linux server – Potential attack?
  • Do metal objects attract lightning?
  • How much missing data is too much (part 2)? statistical power, effective sample size
  • How bad would near constant dreary/gloomy/stormy weather on our or an Earthlike world be for us and the environment?
  • What would be non-slang equivalent of "copium"?
  • Validity of ticket when using alternative train from a different station
  • Purpose of burn permit?
  • How Can this Limit be really Evaluated?
  • Change output language of internal commands like "lpstat"?
  • How do I alter a table by using AFTER in hook update?
  • Optimal Bath Fan Location
  • What did Jesus mean by 'cold water'' in Mtt 10:42?
  • Passport Carry in Taiwan

c std string assignment operator

21.12 — Overloading the assignment operator

Stack Exchange Network

Stack Exchange network consists of 183 Q&A communities including Stack Overflow , the largest, most trusted online community for developers to learn, share their knowledge, and build their careers.

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

std::string implementation

Following is my attempt for a simple implementation for the std string class. Please review my changes and share your feedback.

  • reinventing-the-wheel

Jamal's user avatar

  • 2 \$\begingroup\$ your version can't store '\0' , std::string does \$\endgroup\$ –  phuclv Commented Nov 3, 2016 at 14:34

5 Answers 5

The biggest thing that sticks out is that your string does not have a length member. So when testing for empty or size you have to scan the string to find the result (you don't actually need to do it for empty but you do).

Would it not be easier to keep track of the string length in a member and just return it?

Resetting Memory

Setting memory to zero then copying over it with new values seems completely redundant. Just copy the data into the memory you want.

Because you don't have an explicit length setting memory to zero in other places is required (but do you need to set the whole array to zero? Why not jus the first element. In C-Strings the '\0' character is the string terminator. So if the first character is '\0' then the string is empty and has length zero. At this point what the other characters hold is irrelevant.

Also you are using C functions to do your copying. Use the much better C++ functions. These will use the fastest technique to copy the current type.

Default Parameters

Your first two constructors are identical. You should DRY up your code and use a single constructor. The difference is one has zero parameters and the other takes none and defaults the size:

By using a default parameter you can write this in one function:

This is a sign of bad code design.

You only need to use this if you have shadowed variables. If you have shadowed variables you are writing code that is hard to read and understand because you are using the same name to represent different objects.

So stop using this and turn your compiler warnings up so that it warns you about shadowed variables and then use meaningful unique variable names so that it is obvious what you are doing.

Uninitialized Objects

If your input is not what you expect you don't initialize the object.

Notice in both these cases there is no else. So if you don't fit the condition you do no work. Note in C++ unless you explicitly set the value it has an indeterminate value. Attempting to read an indeterminate value is Undefined Behavior . In your constructors you should explicitly try and set all members (Note: Members that have constructors will be initialized but POD objects don't have constructors int/float/pointers etc...).

Initializer List

You should prefer to use the initializer list in your constructor to set up members. In your code it does not matter because all your members are POD but it is a good habit to get into for all members because when they are not POD (or if somebody changes the type of you member to non POD) this will cause a lot of extra code. This is because the members are initialized by their constructor (if they have one) before the constructor is entered from the initializer list. If you don't explicitly put them in the list the compiler will add them using their default constructor. Subsequent assignment in the constructor code will use the assignment operator for that object.

Boolean Tests

If a value or expression is boolean. You don't need to test it against true/false. That's its value already.

You used the wrong delete. Because you used new [] you must use delete [] to release the memory.

Assignment operator

So if the other string is empty() you are not going to do anything. I think that is a bug. If the other string is empty then this string should also become empty.

You correctly delete the pcString before re-use. BUT what happens if the call to new char[] fails? This can potentially throw an exception. If sombody catches that exception further down the road then you now have an object with pcString pointing at deallocated memory. Not a good idea.

When reallocating. You first allocate the new memory (make sure it works). if it does then you can delete your old memory. It should look like this:

OK. So that is the long way around of doing it. But there is a technique called the copy and swap idiom. That automates Step 1 and Step 3. So all you have to do is write Step 2.

Where did Step 1 and 3 go? If you look at the parameter strInstance . You will notice that we passed it by value. This causes a copy of the original to be created (this is step1) and when the function exits the destructor is called and the parameter is destroyed thus invoking Step 3.

Operator + is not doing what I expect it to.

I would expect operator + to return a completely new object with the strings concatenated. What you have implemented is what I would expect the function operator+= to implement (because you are returning a string reference). If you want to return a new object then you should return by value (drop the &). Yes it looks inefficient to do so but the compiler will see this and perform RVO optimization to elide the copy).

If you look at this in some code.

So I would change the operator to += . Note writing operator+ in terms of operator+= is trivial.

Having a look at your code for operator+ . It looks like you were actually trying to do it correctly. Couple of gotchas.

// This is how I would do it.

Jeffmagma's user avatar

  • \$\begingroup\$ But to me the most glaring shortcoming is that it doesn't implement the std::string API even anywhere near the point of usable. For example at() , operator[] , begin()/end()... , c_str() , substr , copy , swap , find etc are missing. \$\endgroup\$ –  Emily L. Commented Jul 28, 2015 at 16:26
  • \$\begingroup\$ Yes I agree that is an issue. But there are so many basic problems that need to be solved first. Let the OP fix the current issues which are serious bugs then we can discuss interface enhancements in a follow up question. \$\endgroup\$ –  Loki Astari Commented Jul 28, 2015 at 16:45
  • \$\begingroup\$ Downside to using default arguments is that it makes the defaults part of the interface (they have to be in the header, and the compiler will often inline them into code compiled using them). If the library decides to change a default, code that uses the recompiled library without being itself recompiled will still be passing the old default values. By contrast, constructor delegation can be used in the .cpp file without exposing it as part of the interface ; this also saves a tiny amount of work (the defaults aren't repeated at every call site). \$\endgroup\$ –  ShadowRanger Commented Jul 20, 2018 at 19:40

Other answers have handled specific issues, mine will handle larger design issues. Some of my later advice is highly opinionated, but it is motivated by real design problems; be sure to understand the problem before dismissing it.

If you don't like nasty bugs, always use size_t for allocation sizes, not int . Yes, somebody will do it, this is a fatal flaw in the Qt libraries.

You're missing move constructors/assignment. Most likely they should be implemented by moving the ownership logic out to a separate class (if you don't take all of my advice, std::unique_ptr<char[]> would work) and then using the Rule of Zero.

There's no point in providing a find method (this is a flaw of std::string ), you can just use std::find on the iterators (that you need to implement).

Most implementations use char *begin, *end, *end_cap; instead of char *begin; size_t size, cap; , or even just a single string_rep *rep; member which points directly to the string data. and stores size/cap information at offset -1 . Newer implementations often use SSO (Short String Optimization) as well.

You're missing slicing operations. Slicing operations should return a string_view class though, instead of allocating a string .

You're missing operator[] , which most people want from a string. Though I'm not convinced it's useful; I treat strings as opaque blobs rather than containers.

If you choose to have mutable strings (see below), you're missing insert , erase , and replace . In either case, you're missing clear() .

You're missing operator== , operator< , etc. These should allow mixing string with string_view .

In my experience providing operator+ or operator+= on strings is a mistake. Instead, strings should be constructed via one of:

  • a join(separator, string_array, prefix, suffix, last_separator) method.
  • a ostringstream equivalent (which, signficantly, does not need to maintain all the string invariants such as contiguity in its intermediate form).
  • a printf -like string formatting operation.

Likewise, it is exceptionally rare that allowing mutation of a string after construction/assignment is actually useful. This makes the explicit string(size_t) constructor nearly completely useless.

When I implemented my own string classes, I ended up with 10 different classes:

  • XString for a full borrowed slice, equivalent to std::string_view . This is used for most strings in function arguments.
  • ZString for a tail slice, equivalent to XString except guaranteeing that there is a trailing '\0' byte so that it can have a .c_str() method for compatibility with C APIs (including system calls).
  • LString for string literals (via UDL). Acts much like ZString except it is guaranteed to be statically allocated, so nobody needs to own it.
  • VString<n> , which stores a string of fixed maximum size in its own body. sizeof(VString<n>) == n + 1 . Uses a neat trick to store the size in a way that guarantees a '\0' terminator.
  • RString , which owns a string on the heap and uses reference-counting to make copies cheap. If constructed from an LString , detects that and just stores a plain pointer and avoids the allocation and refcount steps. This is the go-to class for long-lived strings.
  • AString , which is like RString but uses SSO. Commonly used for temporary strings to avoid heap allocations, but not often used inside classes since it would often waste spaaace. Since this is opt-in, I can use a large SSO threshold (255), which is useful e.g. for the return value of my snprintf wrapper.
  • SString , an owned full slice of an RString . I ended up not using this much,.
  • TString , an owned tail slice of an RString . Like SString as ZString is to XString .
  • MString , the only class that allows mutation, and that only at the end. Does not provide the standard API that all of the above use. Implemented as a wrapper for std::deque . Often not used in favor of the below.
  • FormatString , a string literal that contains a printf format. Contains lots of nasty hacks with constexpr to let gcc -Wformat work.

All of the above, except for the last two which are special, provide exactly the same public API (except c_str() ) and can be implicitly constructed from each other if it makes sense.

o11c's user avatar

Here are some things you should consider for a std::string-like class:

  • make it a regular object (implement ==, != and strict ordering operators)
  • add support for the compact form of the for loop and standard algorithms (implement begin and end operations returning iterators)
  • Ensure getting the size is a constant-time operation
  • use std::size_t for sizes, instead of relying on int
  • do not provide free access to the data pointer to client code; This is what made the old CString class in MFC be the monster that it was (and a major source for crashing MFC programs); If you want to offer access to the pointer, at least expose it as: const char* const instead of char*

utnapistim's user avatar

I'll focus on the first steps to make it closer to a regular string class. There are many more things (optimizations, etc) to do.

General comments:

Given your implementation, the pointer pcString cannot be NULL. We can assume it is an invariant (which is rather safe, as the user can't modify it, and a bad alloc would generate an exception). So it is possible to remove all the if(this->pcString) checks.

Documentation is needed, as well as adding names to parameters in the .h. For example, only looking at the interface, string(int); is unclear: is the int the new size, or a number to convert to a string?

I recommend putting the size type (here, int ) as a typedef, and then switching to unsigned int , or, better, to std::size_t [edit: it seems keeping it a signed int may be better, see the comment], and make npos public. Motivation: you'll enforce the fact that the size cannot be negative ( npos being simply a special value). If you prefer to keep int as the size type, at least check that the size is >= 0 in string::find .

String can be seen conceptually as a vector<char> . Having an iterator would be nice (but it can take some time to implement it, and may be outside of your scope).

I'd put npos as a public member, to allow if(whole.find(part) != string::npos)

About string(int) : I'd mark this constructor as explicit, to avoid implicit conversion (and possible nasty surprises). Adding a default parameter ( char default char = '\0' ) would be nice.

string(const char*); has a bug: if pcValue == NULL , then pcString is then left uninitialized, thus accessing it later on is Undefined Behavior. If pcValue == NULL , I suggest to make an empty string similar to string(void);

Still in string(const char*); : memset is useless, as you do a memcpy on the whole array right after.

Concerning find(const char*); It should take a string, not a const char*. With only const char*, you can't do:

Also, it should be marked as const .

If you define operator+ and operator= , then operator+= should be present. Tip: it's usually easier to implement operator+= , then use it to implement operator+

operator+ : you should return a string , not a string& . pStrResult shouldn't be allocated on the heap.

operator= and operator< (and all the other comparisons) would be nice.

If you want to see another interface for a string than than the std one, I suggest you check Java's String one, or Qt's QString .

I don't know the C functions very well; I suggest switching to their C++ counterparts.

Toby Speight's user avatar

  • \$\begingroup\$ The standards committee (and Bjorne) has already said it was a mistake to use unsigned int as the parameter for size. But it is too late and they will not change it now. The problem is that it does not stop you using negative numbers (because of the language auto conversion rules the negative number is converted to unsigned number that is very large). But now it is a real unsigned number and impossible to detect if it was originally a negative number. Though your allocation will probably fail at this point). \$\endgroup\$ –  Loki Astari Commented Jul 28, 2015 at 16:19
  • 1 \$\begingroup\$ The standard rule of thumb is use unsigned numbers for bit fields otherwise use a signed number. \$\endgroup\$ –  Loki Astari Commented Jul 28, 2015 at 16:20
  • \$\begingroup\$ @Loki: Very interesting! It's indeed the choice made by Qt. Do you have a link about the standard committee/Bjorne declarations? Also, is the loss of the allocation range (approx. 2 millions vs 4millions on 32bits systems) considered a non-issue? I agree on the failed allocation: the problem stands out (hopefully during the development, not the production) . \$\endgroup\$ –  Armaghast Commented Jul 28, 2015 at 16:38
  • \$\begingroup\$ Yes. But it will take me a while to find. It is a quote at a conference and I only have a link to the video. I'll try and find it by the end of the day. \$\endgroup\$ –  Loki Astari Commented Jul 28, 2015 at 16:42
  • 1 \$\begingroup\$ In this video. channel9.msdn.com/Events/GoingNative/2013/… (The panel contained many members of the committee). At the 40 minutes and 19 second mark Bjarne talks about unsigned ints. At 44 minutes 30 second mark Herb Sutter says Quote: "Unfortunately is a mistake in the STL and standard that we use unsigned integers". \$\endgroup\$ –  Loki Astari Commented Jul 28, 2015 at 19:54

When you do pcString = new char[iSize]; maybe you should delete it before. As I see it, you do lots of new but no delete (except in the destructor).

Maybe, like the std::string, data() should return const char * and you write accessors, so users don't directly access to the pcString .

Why creating the string with a size of 15 ? Wouldn't 1 (with only the character '\0' ) be more self-consistent ?

The rest seems good to me.

Senua's user avatar

Your Answer

Sign up or log in, post as a guest.

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy .

Not the answer you're looking for? Browse other questions tagged c++ strings reinventing-the-wheel or ask your own question .

  • The Overflow Blog
  • Where does Postgres fit in a world of GenAI and vector databases?
  • Featured on Meta
  • We've made changes to our Terms of Service & Privacy Policy - July 2024
  • Bringing clarity to status tag usage on meta sites

Hot Network Questions

  • A string view over a Java String
  • Do metal objects attract lightning?
  • Optimal Bath Fan Location
  • How can you trust a forensic scientist to have maintained the chain of custody?
  • Why doesn't the world fill with time travelers?
  • sudo / sudoers on macOS: regex not working but wildcards/globs are
  • Why does Russia strike electric power in Ukraine?
  • What did Jesus mean by 'cold water'' in Mtt 10:42?
  • Trying to find an old book (fantasy or scifi?) in which the protagonist and their romantic partner live in opposite directions in time
  • What is the difference between using a resistor or a capacitor as current limiter?
  • Can light become a satellite of a black hole?
  • Using "no" at the end of a statement instead of "isn't it"?
  • How to reply to reviewers who ask for more work by responding that the paper is complete as it stands?
  • Is the theory of ordinals in Cantor normal form with just addition decidable?
  • Flight left while checked in passenger queued for boarding
  • What is the significance of bringing the door to Nippur in the Epic of Gilgamesh?
  • A set of five (one is missing!)
  • I'm trying to remember a novel about an asteroid threatening to destroy the earth. I remember seeing the phrase "SHIVA IS COMING" on the cover
  • How are notes named in Japan?
  • The answer is not wrong
  • Why is one of the Intel 8042 keyboard controller outputs inverted?
  • How to attach a 4x8 plywood to a air hockey table
  • Philosophies about how childhood beliefs influence / shape adult thoughts
  • about flag changes in 16-bit calculations on the MC6800

c std string assignment operator

cppreference.com

Move assignment operator.

(C++20)
(C++20)
(C++11)
(C++20)
(C++17)
(C++11)
(C++11)
General topics
(C++11)
-
-expression
block


/
(C++11)
(C++11)
(C++11)
(C++20)
(C++20)
(C++11)

expression
pointer
specifier

specifier (C++11)
specifier (C++11)
(C++11)

(C++11)
(C++11)
(C++11)
General
/ types
types
Members
pointer
-declarations
(C++11)
specifier
specifier
Special member functions
(C++11)
(C++11)
Inheritance
specifier (C++11)
specifier (C++11)

A move assignment operator is a non-template non-static member function with the name operator = that can be called with an argument of the same class type and copies the content of the argument, possibly mutating the argument.

Syntax Explanation Implicitly-declared move assignment operator Implicitly-defined move assignment operator Deleted move assignment operator Trivial move assignment operator Eligible move assignment operator Notes Example Defect reports See also

[ edit ] Syntax

For the formal move assignment operator syntax, see function declaration . The syntax list below only demonstrates a subset of all valid move assignment operator syntaxes.

return-type parameter-list  (1)
return-type parameter-list  function-body (2)
return-type parameter-list-no-default  (3)
return-type parameter-list  (4)
return-type class-name  parameter-list  function-body (5)
return-type class-name  parameter-list-no-default  (6)
class-name - the class whose move assignment operator is being declared, the class type is given as in the descriptions below
parameter-list - a of only one parameter, which is of type , const T&&, volatile T&& or const volatile T&&
parameter-list-no-default - a of only one parameter, which is of type , const T&&, volatile T&& or const volatile T&& and does not have a default argument
function-body - the of the move assignment operator
return-type - any type, but is favored in order to allow chaining asssignments

[ edit ] Explanation

The move assignment operator is called whenever it is selected by overload resolution , e.g. when an object appears on the left-hand side of an assignment expression, where the right-hand side is an rvalue of the same or implicitly convertible type.

Move assignment operators typically "steal" the resources held by the argument (e.g. pointers to dynamically-allocated objects, file descriptors, TCP sockets, I/O streams, running threads, etc.), rather than make copies of them, and leave the argument in some valid but otherwise indeterminate state. For example, move-assigning from a std::string or from a std::vector may result in the argument being left empty. This is not, however, a guarantee. A move assignment is less, not more restrictively defined than ordinary assignment; where ordinary assignment must leave two copies of data at completion, move assignment is required to leave only one.

[ edit ] Implicitly-declared move assignment operator

If no user-defined move assignment operators are provided for a class type, and all of the following is true:

  • there are no user-declared copy constructors ;
  • there are no user-declared move constructors ;
  • there are no user-declared copy assignment operators ;
  • there is no user-declared destructor ,

then the compiler will declare a move assignment operator as an inline public member of its class with the signature T & T :: operator = ( T && ) .

A class can have multiple move assignment operators, e.g. both T & T :: operator = ( const T && ) and T & T :: operator = ( T && ) . If some user-defined move assignment operators are present, the user may still force the generation of the implicitly declared move assignment operator with the keyword default .

The implicitly-declared (or defaulted on its first declaration) move assignment operator has an exception specification as described in dynamic exception specification (until C++17) noexcept specification (since C++17) .

Because some assignment operator (move or copy) is always declared for any class, the base class assignment operator is always hidden. If a using-declaration is used to bring in the assignment operator from the base class, and its argument type could be the same as the argument type of the implicit assignment operator of the derived class, the using-declaration is also hidden by the implicit declaration.

[ edit ] Implicitly-defined move assignment operator

If the implicitly-declared move assignment operator is neither deleted nor trivial, it is defined (that is, a function body is generated and compiled) by the compiler if odr-used or needed for constant evaluation (since C++14) .

For union types, the implicitly-defined move assignment operator copies the object representation (as by std::memmove ).

For non-union class types, the move assignment operator performs full member-wise move assignment of the object's direct bases and immediate non-static members, in their declaration order, using built-in assignment for the scalars, memberwise move-assignment for arrays, and move assignment operator for class types (called non-virtually).

The implicitly-defined move assignment operator for a class is if

is a , and that is of class type (or array thereof), the assignment operator selected to move that member is a constexpr function.
(since C++14)
(until C++23)

The implicitly-defined move assignment operator for a class is .

(since C++23)

As with copy assignment, it is unspecified whether virtual base class subobjects that are accessible through more than one path in the inheritance lattice, are assigned more than once by the implicitly-defined move assignment operator:

[ edit ] Deleted move assignment operator

The implicitly-declared or defaulted move assignment operator for class T is defined as deleted if any of the following conditions is satisfied:

  • T has a non-static data member of a const-qualified non-class type (or possibly multi-dimensional array thereof).
  • T has a non-static data member of a reference type.
  • T has a potentially constructed subobject of class type M (or possibly multi-dimensional array thereof) such that the overload resolution as applied to find M 's move assignment operator
  • does not result in a usable candidate, or
  • in the case of the subobject being a variant member , selects a non-trivial function.

A deleted implicitly-declared move assignment operator is ignored by overload resolution .

[ edit ] Trivial move assignment operator

The move assignment operator for class T is trivial if all of the following is true:

  • It is not user-provided (meaning, it is implicitly-defined or defaulted);
  • T has no virtual member functions;
  • T has no virtual base classes;
  • the move assignment operator selected for every direct base of T is trivial;
  • the move assignment operator selected for every non-static class type (or array of class type) member of T is trivial.

A trivial move assignment operator performs the same action as the trivial copy assignment operator, that is, makes a copy of the object representation as if by std::memmove . All data types compatible with the C language (POD types) are trivially move-assignable.

[ edit ] Eligible move assignment operator

A move assignment operator is eligible if it is not deleted.

(until C++20)

A move assignment operator is eligible if all following conditions are satisfied:

(if any) are satisfied. than any other move assignment operator.
(since C++20)

Triviality of eligible move assignment operators determines whether the class is a trivially copyable type .

[ edit ] Notes

If both copy and move assignment operators are provided, overload resolution selects the move assignment if the argument is an rvalue (either a prvalue such as a nameless temporary or an xvalue such as the result of std::move ), and selects the copy assignment if the argument is an lvalue (named object or a function/operator returning lvalue reference). If only the copy assignment is provided, all argument categories select it (as long as it takes its argument by value or as reference to const, since rvalues can bind to const references), which makes copy assignment the fallback for move assignment, when move is unavailable.

It is unspecified whether virtual base class subobjects that are accessible through more than one path in the inheritance lattice, are assigned more than once by the implicitly-defined move assignment operator (same applies to copy assignment ).

See assignment operator overloading for additional detail on the expected behavior of a user-defined move-assignment operator.

[ edit ] Example

[ edit ] defect reports.

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
C++11 the conditions where defaulted move assignment operators are
defined as deleted did not consider multi-dimensional array types
consider these types
C++11 a defaulted move assignment operator that would
call a non-trivial copy assignment operator was
deleted; a defaulted move assignment operator that
is deleted still participated in overload resolution
allows call to such
copy assignment
operator; made ignored
in overload resolution
C++11 specification for a defaulted move assignment operator
involving a virtual base class was missing
added
C++11 a volatile subobject made of a defaulted
move assignment operator non-trivial ( )
triviality not affected
C++11 a defaulted move assignment operator for class
was not defined as deleted if is abstract and has
non-move-assignable direct virtual base classes
the operator is defined
as deleted in this case
C++20 a move assignment operator was not eligible if there
is another move assignment operator which is more
constrained but does not satisfy its associated constraints
it can be eligible in this case
C++11 the implicitly-defined move assignment operator for
union types did not copy the object representation
they copy the object
representation

[ edit ] See also

  • constructor
  • converting constructor
  • copy assignment
  • copy constructor
  • default constructor
  • aggregate initialization
  • constant initialization
  • copy initialization
  • default initialization
  • direct initialization
  • list initialization
  • reference initialization
  • value initialization
  • zero initialization
  • move constructor
  • Recent changes
  • Offline version
  • What links here
  • Related changes
  • Upload file
  • Special pages
  • Printable version
  • Permanent link
  • Page information
  • In other languages
  • This page was last modified on 11 January 2024, at 20:29.
  • Privacy policy
  • About cppreference.com
  • Disclaimers

Powered by MediaWiki

  • DSA Tutorial
  • Data Structures
  • Linked List
  • Dynamic Programming
  • Binary Tree
  • Binary Search Tree
  • Divide & Conquer
  • Mathematical
  • Backtracking
  • Branch and Bound
  • Pattern Searching

std::move in Utility in C++ | Move Semantics, Move Constructors and Move Assignment Operators

Prerequisites:

  • lvalue reference
  • rvalue reference
  • Copy Semantics (Copy Constructor)

References:

In C++ there are two types of references-

  • An lvalue is an expression that will appear on the left-hand side or on the right-hand side of an assignment.
  • Simply, a variable or object that has a name and memory address.
  • It uses one ampersand (&).
  • An rvalue is an expression that will appear only on the right-hand side of an assignment.
  • A variable or object has only a memory address (temporary objects).
  • It uses two ampersands (&&).

Move Constructor And Semantics:

The move constructor was introduced in C++11 . The need or purpose of a move constructor is to steal or move as many resources as it can from the source (original) object , as fast as possible, because the source does not need to have a meaningful value anymore, and/or because it is going to be destroyed in a moment anyway. So that one can avoid unnecessarily creating copies of an object and make efficient use of the resources

While one can steal the resources, but one must leave the source (original) object in a valid state where it can be correctly destroyed.

Move constructors typically “steal” the resource of the source (original) object rather than making several copies of them, and leaves the source object in a “valid but unspecified state”.

The copy constructor uses the lvalue references which are marked with one ampersand (&) while the move constructor uses the rvalue references are marked with two ampersands (&&).

std::move() is a function used to convert an lvalue reference into the rvalue reference. Used to move the resources from a source object i.e. for efficient transfer of resources from one object to another. std::move() is defined in the <utility> header .
template< class T >  typename std::remove_reference<T>::type&& move(T&& t) noexcept;                 (since C++11)(until C++14) template< class T >  constexpr std::remove_reference_t<T>&& move(T&& t) noexcept                       (since C++14)

Example: Below is the C++ program to show what happens without using move semantics i.e. before C++11.

Explanation:

Assuming the program is compiled and executed using a compiler that doesn’t support move semantics. In the main() function,  

1. std::vector<std::string> vecString;- An empty vector is created with no elements in it.  2. vecString = createAndInsert();- The createAndInsert() function is called. 3. In createAndInsert() function-

  • std::vector<std::string> vec;- Another new empty vector named as vec is created.
  • vec.reserve(3);- Reserving the size of 3 elements.
  • std::string str(“Hello”);- A string named as str initialized with a “Hello”.
  • vec.push_back( str );- A string is passed by value into the vector vec. Therefore a (deep) copy of str will be created and inserted into the vec by calling a copy constructor of the String class.
  • A temporary object will be created (str + str) with its own separate memory.
  • This temporary object is inserted into vector vec which is passed by value again means that a (deep) copy of the temporary string object will be created.
  • As of now, the temporary object is no longer needed hence it will be destroyed.

Note: Here, we unnecessarily allocate & deallocate the memory of the temporary string object. which can be optimized (improved) further just by moving the data from the source object. 

  • vec.push_back( str );- The same process as of Line no. 5 will be carried out. Remember at this point the str string object will be last used.
  • Firstly, the string object str will be destroyed because the scope is left where it is declared.
  • Secondly, a local vector of string i.e vec is returned. As the return type of the function is not by a reference. Hence, a deep copy of the whole vector will be created by allocating at a separate memory location and then destroys the local vec object because the scope is left where it is declared.
  • Finally, the copy of the vector of strings will be returned to the caller main() function.
  • At the last, after returning to the caller main() function, simply printing the elements of the local vecString vector.

Example: Below is the C++ program to implement the above concept using move semantics i.e. since C++11 and later. 

Here, in order to use the move semantics. The compiler must support the C++11 standards or above. The story of execution for the main() function and createAndInsert() function remains the same till the line vec.push_back( str );

A question may arise why the temporary object is not moved to vector vec using std::move(). The reason behind it is the push_back() method of the vector. Since C++11 the push_back() method has been provided with its new overloaded version.

The push_back() method takes its parameter by const reference, but since std::vector stores its elements by value, a deep copy of str is created and inserted into the vector. This involves calling the copy constructor of std::string.

Syntax:  

constexpr void push_back(const T& value);                                        (since C++20) void push_back(T&& value);                                                              (since C++11) (until C++20) void push_back(const T& value);                                                        (until C++20) constexpr void push_back(T&& value);                                              (since C++20)
  • A temporary object str + str is created.
  • This temporary object is then passed to vec.push_back(). Since std::vector stores elements by value, it will create a copy of this temporary object.
  • The temporary object is destroyed as it is no longer needed.
  • vec.push_back(std::move(str));-
  • std::move() casts str to an rvalue reference, and push_back() will move the contents of str into the vector, leaving str in a valid but unspecified state.
  • return vec; – This typically involves returning the local vector vec. While a deep copy of the vector would normally be created, modern compilers often use Return Value Optimization (RVO) to eliminate unnecessary copying.

A question may arise while returning the vec object to its caller. As it is not required anymore and also a whole temporary object of a vector is going to be created and also local vector vec will be destroyed, then why std::move() is not used to steal the value and return it.  Its answer is simple and obvious, there is optimization at the compiler level known as (Named) Return Value Object, more popularly known as RVO . 

Some Fallback Of Move Semantics:  

  • It doesn’t make any sense to steal or move the resources of a const object.
  • See constObjectCallFunc() function in the below program
  • See baz() function in the below program
  • See bar() function in the below program

Note: The foo() function have all necessary types of arguments.

Below is the C++ program to implement all the above concepts- 

Summary:  

  • Move semantics allows us to optimize the copying of objects, where we do not need the worth. It is often used implicitly (for unnamed temporary objects or local return values) or explicitly with std::move().
  • std::move() means “no longer need this value” .
  • An object marked with std::move() is never partially destroyed. i.e. The destructor will be called to destroy the object properly.

Please Login to comment...

Similar reads.

  • C++ Programs
  • Competitive Programming
  • Blogathon-2021
  • Constructors
  • SUMIF in Google Sheets with formula examples
  • How to Get a Free SSL Certificate
  • Best SSL Certificates Provider in India
  • Elon Musk's xAI releases Grok-2 AI assistant
  • Content Improvement League 2024: From Good To A Great Article

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

  • <cassert> (assert.h)
  • <cctype> (ctype.h)
  • <cerrno> (errno.h)
  • C++11 <cfenv> (fenv.h)
  • <cfloat> (float.h)
  • C++11 <cinttypes> (inttypes.h)
  • <ciso646> (iso646.h)
  • <climits> (limits.h)
  • <clocale> (locale.h)
  • <cmath> (math.h)
  • <csetjmp> (setjmp.h)
  • <csignal> (signal.h)
  • <cstdarg> (stdarg.h)
  • C++11 <cstdbool> (stdbool.h)
  • <cstddef> (stddef.h)
  • C++11 <cstdint> (stdint.h)
  • <cstdio> (stdio.h)
  • <cstdlib> (stdlib.h)
  • <cstring> (string.h)
  • C++11 <ctgmath> (tgmath.h)
  • <ctime> (time.h)
  • C++11 <cuchar> (uchar.h)
  • <cwchar> (wchar.h)
  • <cwctype> (wctype.h)

Containers:

  • C++11 <array>
  • <deque>
  • C++11 <forward_list>
  • <list>
  • <map>
  • <queue>
  • <set>
  • <stack>
  • C++11 <unordered_map>
  • C++11 <unordered_set>
  • <vector>

Input/Output:

  • <fstream>
  • <iomanip>
  • <ios>
  • <iosfwd>
  • <iostream>
  • <istream>
  • <ostream>
  • <sstream>
  • <streambuf>

Multi-threading:

  • C++11 <atomic>
  • C++11 <condition_variable>
  • C++11 <future>
  • C++11 <mutex>
  • C++11 <thread>
  • <algorithm>
  • <bitset>
  • C++11 <chrono>
  • C++11 <codecvt>
  • <complex>
  • <exception>
  • <functional>
  • C++11 <initializer_list>
  • <iterator>
  • <limits>
  • <locale>
  • <memory>
  • <new>
  • <numeric>
  • C++11 <random>
  • C++11 <ratio>
  • C++11 <regex>
  • <stdexcept>
  • <string>
  • C++11 <system_error>
  • C++11 <tuple>
  • C++11 <type_traits>
  • C++11 <typeindex>
  • <typeinfo>
  • <utility>
  • <valarray>

class templates

  • basic_string
  • char_traits
  • C++11 u16string
  • C++11 u32string
  • C++11 stold
  • C++11 stoll
  • C++11 stoul
  • C++11 stoull
  • C++11 to_string
  • C++11 to_wstring
  • basic_string::~basic_string
  • basic_string::basic_string

member functions

  • basic_string::append
  • basic_string::assign
  • basic_string::at
  • C++11 basic_string::back
  • basic_string::begin
  • basic_string::c_str
  • basic_string::capacity
  • C++11 basic_string::cbegin
  • C++11 basic_string::cend
  • basic_string::clear
  • basic_string::compare
  • basic_string::copy
  • C++11 basic_string::crbegin
  • C++11 basic_string::crend
  • basic_string::data
  • basic_string::empty
  • basic_string::end
  • basic_string::erase
  • basic_string::find
  • basic_string::find_first_not_of
  • basic_string::find_first_of
  • basic_string::find_last_not_of
  • basic_string::find_last_of
  • C++11 basic_string::front
  • basic_string::get_allocator
  • basic_string::insert
  • basic_string::length
  • basic_string::max_size
  • basic_string::operator[]
  • basic_string::operator+=
  • basic_string::operator=
  • C++11 basic_string::pop_back
  • basic_string::push_back
  • basic_string::rbegin
  • basic_string::rend
  • basic_string::replace
  • basic_string::reserve
  • basic_string::resize
  • basic_string::rfind
  • C++11 basic_string::shrink_to_fit
  • basic_string::size
  • basic_string::substr
  • basic_string::swap

member constants

  • basic_string::npos

non-member overloads

  • getline (basic_string)
  • operator+ (basic_string)
  • operator<< (basic_string)
  • >/" title="operator>> (basic_string)"> operator>> (basic_string)
  • relational operators (basic_string)
  • swap (basic_string)

std:: basic_string ::operator=

string (1)
c-string (2)
character (3)
string (1)
c-string (2)
character (3)
initializer list (4)
move (5)

Return Value

main () { std::string str1, str2, str3; str1 = ; str2 = ; str3 = str1 + str2; std::cout << str3 << ; 0; }

Iterator validity

Exception safety.

std::string operator=

  • since C++23
  • since C++20
  • since C++17
  • since C++11
  • until C++11

Replaces the contents of the string.

(1) Copy assignment operator. Replaces the contents with a copy of the contents of other .

If *this and str are the same object, this function has no effect.

(2) Move assignment operator. Replaces the contents with those of other using move semantics (i.e. the data in other is moved from other into this container).

other is in a valid but unspecified state afterwards.

If std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value is true , the allocator of *this is replaced by a copy of that of str .

If it is false and the allocators of *this and str do not compare equal, *this cannot take ownership of the memory owned by str and must assign each character individually, allocating additional memory using its own allocator as needed.

Unlike other container move assignments, references , pointers , and iterators to str may be invalidated.

(3) Replaces the contents with those of null-terminated character string pointed to by s as if by assign(s, Traits::length(s)) .

(4) Replaces the contents with character ch as if by assign(std::addressof(ch), 1) .

(5) Replaces the contents with those of the initializer list ilist as if by assign(ilist.begin(), ilist.size()) .

(6) Implicitly converts t to a string view sv as if by std::basic_string_view<CharT, Traits> sv = t; , then replaces the contents with those of the sv as if by assign(sv) .

This overload participates in overload resolution only if std::is_convertible_v<const StringViewLike&, std::basic_string_view<CharT, Traits>> is true and std::is_convertible_v<const StringViewLike&, const CharT*> is false .

(7) Deleted constructor for std::nullptr_t makes it so that std::string cannot be assigned from nullptr .

Parameters ​

  • ch - value to initialize characters of the string with
  • str - string to be used as source to initialize the string with
  • s - pointer to a null-terminated character string to use as source to initialize the string with
  • ilist - std::initializer_list to initialize the string with
  • t - object convertible to std::basic_string_view to initialize the string with

Return value ​

Complexity ​.

  • (1) Linear in the size of str - O(str.size()) .
  • (2) Linear in the size of *this - O(size()) . If allocators do not compare equal and do not propagate, then also linear in the size of str - O(size() + str.size()) .
  • (3) Linear in the size of s - O(s.size()) .
  • (4) Constant - O(1) .
  • (5) Linear in size of ilist - O(ilist.size()) .

Exceptions ​

  • (2) noexcept specification:

If the operation would result in size() > max_size() , throws std::length_error .

  • Return value

IMAGES

  1. Assignment Operators in C

    c std string assignment operator

  2. C# Assignment Operator

    c std string assignment operator

  3. std::string::append vs std::string::push_back() vs Operador += en C++

    c std string assignment operator

  4. PPT

    c std string assignment operator

  5. Operators in C#

    c std string assignment operator

  6. Assignment Operator Overloading in C++

    c std string assignment operator

COMMENTS

  1. c++11

    for (auto _ : state) {. str = base; } } BENCHMARK(string_assign_operator); Here is the graphical comparitive solution. It seems like both the methods are equally faster. The assignment operator has better results. Use string::assign only if a specific position from the base string has to be assigned.

  2. c++

    std::string a = std::string( "simple_text" ); At first a temporary object is created std::string ( "simple_text" ); with using constructor with parameter const char * and then this object is moved into a by using the move constructor. However the C++ Standard allows to eliminate the call of the move constructor.

  3. std::basic_string<CharT,Traits,Allocator>:: operator=

    basic_string& operator=(std::nullptr_t)= delete; (7) (since C++23) Replaces the contents of the string. 1) Replaces the contents with a copy of str. If *this and str are the same object, this function has no effect. 2) Replaces the contents with those of str using SequenceContainer 's move assignment semantics.

  4. 22.5

    22.5 — std::string assignment and swapping. Alex September 16, 2022. String assignment. The easiest way to assign a value to a string is to use the overloaded operator= function. There is also an assign () member function that duplicates some of this functionality. string& string::operator= (const string& str)

  5. Does std::string::assign takes "ownership" of the string?

    Does s.assign allocate a new buffer and copy the string into it or it assumes ownership of the pointer; The STL string method assign will copy the character array into the string. If the already allocated buffer inside the string is insufficient it will reallocate the memory internally. The STL string will not take ownership of the original array.

  6. string

    Assigns a new value to the string, replacing its current contents. (1) string Copies str. (2) substring Copies the portion of str that begins at the character position subpos and spans sublen characters (or until the end of str, if either str is too short or if sublen is string::npos). (3) c-string Copies the null-terminated character sequence (C-string) pointed by s.

  7. std::string::assign() in C++

    The member function assign () is used for the assignments, it assigns a new value to the string, replacing its current contents. Syntax 1: Assign the value of string str. string& string::assign (const string& str) str : is the string to be assigned. Returns : *this.

  8. Assignment operators

    for assignments to class type objects, the right operand could be an initializer list only when the assignment is defined by a user-defined assignment operator. removed user-defined assignment constraint. CWG 1538. C++11. E1 ={E2} was equivalent to E1 = T(E2) ( T is the type of E1 ), this introduced a C-style cast. it is equivalent to E1 = T{E2}

  9. operator overloading

    In those situations where copy assignment cannot benefit from resource reuse (it does not manage a heap-allocated array and does not have a (possibly transitive) member that does, such as a member std::vector or std::string), there is a popular convenient shorthand: the copy-and-swap assignment operator, which takes its parameter by value (thus working as both copy- and move-assignment ...

  10. C++

    Assigns a new value to the string, replacing its current contents. (See member function assign for additional assignment options). Parameters str A string object, whose value is either copied (1) or moved (5) if different from *this (if moved, str is left in an unspecified but valid state). s Pointer to a null-terminated sequence of characters.

  11. string

    Strings are objects that represent sequences of characters. The standard string class provides support for such objects with an interface similar to that of a standard container of bytes, but adding features specifically designed to operate with strings of single-byte characters. The string class is an instantiation of the basic_string class template that uses char (i.e., bytes) as its ...

  12. 21.12

    21.12 — Overloading the assignment operator. Alex July 22, 2024. The copy assignment operator (operator=) is used to copy values from one object to another already existing object. As of C++11, C++ also supports "Move assignment". We discuss move assignment in lesson 22.3 -- Move constructors and move assignment .

  13. c++

    So that is the long way around of doing it. But there is a technique called the copy and swap idiom. That automates Step 1 and Step 3. So all you have to do is write Step 2. string& string::operator=(string strInstance) {. std::swap(strInstance.pcString, pcString); this->iCapacity = strInstance.iCapacity;

  14. Copy assignment operator

    the copy assignment operator selected for every non-static class type (or array of class type) member of T is trivial. A trivial copy assignment operator makes a copy of the object representation as if by std::memmove. All data types compatible with the C language (POD types) are trivially copy-assignable.

  15. Move assignment operator

    The move assignment operator is called whenever it is selected by overload resolution, e.g. when an object appears on the left-hand side of an assignment expression, where the right-hand side is an rvalue of the same or implicitly convertible type.. Move assignment operators typically "steal" the resources held by the argument (e.g. pointers to dynamically-allocated objects, file descriptors ...

  16. string

    A string object, whose value is copied at the end. s. Pointer to a null-terminated sequence of characters. The sequence is copied at the end of the string. c. A character, which is appended to the current value of the string. il. An initializer_list object.

  17. std::move in Utility in C++

    In C++, the assignment operator forms the backbone of many algorithms and computational processes by performing a simple operation like assigning a value to a variable. ... they serve different requirements. In this article, we will look at some major differences between the std::wstring and std::string in C++. Wide String in C++The std ...

  18. basic_string

    Assigns a new value to the string, replacing its current contents. (See member function assign for additional assignment options). Parameters str A basic_string object of the same type (with the same class template arguments charT, traits and Alloc), whose value is either copied (1) or moved (5) if different from *this (if moved, str is left in an unspecified but valid state).

  19. string<...>::operator=

    (7) Deleted constructor for std::nullptr_t makes it so that std::string cannot be assigned from nullptr. Parameters . ch - value to initialize characters of the string with; str - string to be used as source to initialize the string with; s - pointer to a null-terminated character string to use as source to initialize the string with; ilist - std::initializer_list to initialize the string with