12

Starting in C++11, one can write something like

#include <vector>
#include <string>

struct S
{

    S(int x, const std::string& s)
        : x(x)
        , s(s)
    {
    }

    int x;
    std::string s;

};

// ...

std::vector<S> v;

// add new object to the vector v
// only parameters of added object's constructor are passed to the function
v.emplace_back(1, "t");

Is there any C# analogue of C++ functions like emplace or emplace_back for container classes (System.Collections.Generic.List)?

Update: In C# similar code might be written as list.EmplaceBack(1, "t"); instead of list.Add(new S(1, "t"));. It would be nice not to remember a class name and write new ClassName in such situations every time.

Constructor
  • 7,273
  • 2
  • 24
  • 66
  • @PatrickHofman: 2 things. It constructs the object directly in place at its intended location in the vector (as opposed to copying or moving a pre-existing object), and it forwards the arguments directly to the object's constructor. – Benjamin Lindley Mar 14 '16 at 11:09
  • 2
    Aren't all C# objects always dynamically allocated, basically always pointer-held? What would such an emplace functionality bring? – Angew is no longer proud of SO Mar 14 '16 at 11:10
  • 1
    @Angew For `struct` data types it would be marginally faster. For big `struct` data types it would be probably faster. But `struct` data types shouldn't be big, so it would be a solution looking for a problem :-) – xanatos Mar 14 '16 at 11:11
  • actually for a list it's the same thing as myList.Add(new S(1,"t")); edit : from cppReference Appends a new element to the end of the container. The element is constructed through std::allocator_traits::construct, which typically uses placement-new to construct the element in-place at the location provided by the container. The arguments args... are forwarded to the constructor as std::forward(args).... – Boo Mar 14 '16 at 11:13
  • 2
    @Angew To reduce the code size. With emplace you don't need to write `v.insert(S(1, "t"));` in C++. In C# it might be written like `list.EmplaceBack(1, "t");` instead of `list.Add(new S(1, "t"));`. – Constructor Mar 14 '16 at 11:14
  • @Boo With hypothetical `EmplaceBack` you won't need to write `new ClassName` every time. – Constructor Mar 14 '16 at 11:16
  • 2
    It would be better if you write `C#` implementation and state what is wrong with it. – Sinatr Mar 14 '16 at 11:17
  • @Boo 1) Class names are usually long enough. 2) You always need to remember it while you are writing construction with `Add` function. 3) It is possible to choose shorter name for such function. – Constructor Mar 14 '16 at 11:25
  • @Sinatr The question is updated. – Constructor Mar 14 '16 at 11:45
  • 1
    If you feel that it is a valuable feature for C# you can always add a feature request at http://connect.microsoft.com. However I'd be very, very surprised if it makes it to the final list of implemented features. There's already a way to do it, very few has complained about having to type the class name in the 17 years of C#'s existence, and it serves no practical purpose in C# (unlike C++). Plus the amount of design, testing and documentation, likely far outweigh the perceived benefit. Get used to typing class names... – D Stanley Mar 14 '16 at 12:54
  • 1
    In C#9 you can do `new()` when the compiler can determine the type. – mhand Aug 15 '21 at 09:04
  • @mhand Could you provide an example of source code using such `new()` operator? – Constructor Aug 16 '21 at 18:15

4 Answers4

6

In general there is nothing similar in C#, and its need is much less than in C++.

In C# when you have a List<SomeReferenceType> what you really have is a List<ReferenceToSomeType>, so a list of references, with the size of each element of 4 or 8 bytes (see How big is an object reference in .NET?). Copying a reference doesn't cause the underlying object to be duplicated, so it is very fast (you are copying around 4 or 8 bytes, and the processor is optimized for this operation, because that is the size of the native pointer of the processor). So when you someList.Add(someReference) what you are doing is adding a reference to your List<>.

In C++ when you have a std::vector<SomeType> what you have is a vector of SomeType, with the size of each element equal to sizeof(SomeType). Inserting a new element in std::vector<> will cause the element you are inserting to be duplicated (cloned, copied... choose a verb you like). This is an expensive operation.

Quite often the pattern you use is that you create an object just to insert it into a std::vector<>. To optimize this operation in C++11 they added two ways to do it: the std::vector<>::emplace method and support by the std::vector<> of the move semantic. The difference is that the move semantic must be supported by the SomeType type (you need a move constructor with the noexcept specifier), while every type supports the emplace (that in the end simply used placement constructor).

Community
  • 1
  • 1
xanatos
  • 109,618
  • 12
  • 197
  • 280
  • It's necessary to reduce code size: with hypothetical `EmplaceBack` you don't need to write `new ClassName` in `Add` statement every time. – Constructor Mar 14 '16 at 11:31
  • 4
    @Constructor: If all it did in C++ was save you a little typing, it wouldn't exist, because that certainly is not one of the motivations for it. – Benjamin Lindley Mar 14 '16 at 11:33
  • 1
    @BenjaminLindley Of course, you are right. But it is so good not to write `ClassName` (C++) or `new ClassName` (C#) in such situations every time. – Constructor Mar 14 '16 at 11:40
  • 1
    @Constructor There is at least another reason why in C# it would be less usefull... In C++ if you try to put a `DerivedType` object inside a `std::vector` [very bad things happens](http://stackoverflow.com/questions/274626/what-is-object-slicing), and no one wants these bad things. In C# it is perfectly ok to put a reference to `DerivedType` in a `BaseType` variable/container (and it is a common pattern). So having in a `List` an `Emplace()` that can only build `BaseType` would be less useful. – xanatos Mar 14 '16 at 11:45
  • @xanatos Yes, you are right. But at least in 95% of cases you add to the list objects of the same type you have specified at the list's declaration, so such function might be useful enough. – Constructor Mar 14 '16 at 11:48
  • @Constructor Not all the patterns that could be useful are implemented in C#. This would require the support for parameterized `new()` constraints for generic, plus variadic generics (plus some glue between the two). C++ is much more advanced in the "compile time metaprogramming" than C# – xanatos Mar 14 '16 at 11:59
  • @xanatos Yes, I began to realize that sad thing. Is there any .NET language with metaprogramming capabilities as powerful as such that C++ have? – Constructor Mar 14 '16 at 12:03
  • @Constructor I do feel very much that you are exchanging what is the side effect (no need to explicitly name the class name) for the real reason (no copy during insertion). C++ is much more verbose than C#. All its meta-programming power often sticks its "ugly" head out and then you have lines of code full of `std::move`, `std::forward` and other esoteric things. – xanatos Mar 14 '16 at 12:08
  • @xanatos This side effect does a program code mush nicer. For me it is better to have an ugly way to do something than not to have any one. IMHO, C++ metaprogramming is ugly but C# language restrictions are ugly, too, in this case. I want to avoid code duplication in all its forms. – Constructor Mar 14 '16 at 12:18
  • Yes, but what if you have a List? It would still be useful! – user643011 Mar 31 '20 at 22:23
4

You can a bit improve @Boo variant with extenstion.
You can create object instance with Activator.CreateInstance so it make solution more generic.

public static class ListExtension
{
    public static void Emplace<S>(this IList<S> list, params object[] parameters)
    {
        list.Add((S)Activator.CreateInstance(typeof(S), parameters));
    }
}

Note: not checked type and count parameters, so if you do something wrong, you get errors just in run-time

Community
  • 1
  • 1
Grundy
  • 13,356
  • 3
  • 35
  • 55
-1

in c# you can use extension method to achive what you want

public static class ListExtension
{
    public static void Emplace(this IList<S> list, int x, string s)
    {
        list.Add(new S(x, s));
    }
}

then use it like this

myList.Emplace(1,"t");
Boo
  • 663
  • 5
  • 10
-1

It seems you have following problems:

  1. It's longer to type by "new S". But "add" is shorter than "emplace". Type is added for you by intellisense (simply press Enter after typing "new "):


  1. You are afraid to write a wrong type. Well you can't with List<T>. Intellisense will help you to type and compiler will not allow wrong type to be added at compile time anyway.

  2. Performance: see @Xanatos answer.

list.Add(new S(1, "t")); is perfectly fine to use.

Conclusion: we don't need emplace in C#.

Community
  • 1
  • 1
Sinatr
  • 20,892
  • 15
  • 90
  • 319
  • A simple question: why do I need to type anything that can be added by intellicence (a program, not a human)? It is not a programmer's job to do things that can be automated at IDE/compiler level. – Constructor Mar 14 '16 at 12:33
  • I don't understand you comment. Can you give an example explaining what you mean please? Intellisense is not a human, so it can only offer assistance at certain points (e.g. typing `.` will show list of accessible members of what is to the left). It might be possible to *automate* `emplace` (using [pre-processor](http://stackoverflow.com/q/709463/1997232), e.g. VS extension, not sure here), but I don't see a single valid point why would I want it. – Sinatr Mar 14 '16 at 12:49
  • You wrote: "Type is added for you by intellisense." If intellisense is smart enough to add a type why should I do it myself? It can be simply done at a compiler level. – Constructor Mar 14 '16 at 13:01
  • I see your point now. I would rather prefer `add` + `new` myself even if there would be `emplace` mechanics. The wrong/boring things are getting constantly addressed (see [`C# 6.0`](https://github.com/dotnet/roslyn/wiki/New-Language-Features-in-C%23-6)). Would that very minor thing you want ever get into the list? I doubt. – Sinatr Mar 14 '16 at 13:20