নতুন ছাড়া সি ++ তে কনস্ট্রাক্টরকে কল করা হচ্ছে


142

আমি প্রায়শই দেখেছি যে লোকেরা সি ++ ব্যবহার করে অবজেক্ট তৈরি করে

Thing myThing("asdf");

এর পরিবর্তে:

Thing myThing = Thing("asdf");

এটি কমপক্ষে যতক্ষণ কোনও টেম্পলেট জড়িত না থাকে ততক্ষণ এটি (জিসিসি ব্যবহার করে) কাজ করে বলে মনে হচ্ছে। আমার প্রশ্ন এখন, প্রথম লাইনটি সঠিক এবং যদি তাই হয় তবে আমি এটি ব্যবহার করব?


25
হয় ফর্ম নতুন ছাড়া হয়।
ড্যানিয়েল দারানাস

13
দ্বিতীয় ফর্মটি অনুলিপি নির্মাণকারী ব্যবহার করবে তাই না, তারা সমতুল্য নয়।
এডওয়ার্ড স্ট্রেঞ্জ

আমি এটি দিয়ে কিছুটা খেলেছি, প্রথম উপায়ে কখনও কখনও ব্যর্থ হয়ে যায় যখন টেম্পলেটগুলি প্যারামিটারলেস কনস্ট্রাক্টরগুলির সাথে ব্যবহৃত হয় ..
নিলস

1
ওহ এবং আমি "নিস প্রশ্ন" ব্যাজটি পেয়েছি, কী লজ্জা!
নীল

উত্তর:


153

উভয় লাইন আসলেই সঠিক তবে সূক্ষ্মভাবে বিভিন্ন জিনিস করে।

প্রথম লাইন বিন্যাসের কনস্ট্রাক্টরকে কল করে স্ট্যাকের উপরে একটি নতুন অবজেক্ট তৈরি করে Thing(const char*)

দ্বিতীয়টি কিছুটা জটিল। এটি মূলত নিম্নলিখিতগুলি করে

  1. Thingকনস্ট্রাক্টর ব্যবহার করে টাইপের একটি অবজেক্ট তৈরি করুনThing(const char*)
  2. Thingকনস্ট্রাক্টর ব্যবহার করে টাইপের একটি অবজেক্ট তৈরি করুনThing(const Thing&)
  3. ~Thing()পদক্ষেপ # 1 এ তৈরি করা অবজেক্টটিতে কল করুন

7
আমি অনুমান করি যে এই ধরণের ক্রিয়াগুলি অনুকূলিত হয় এবং তাই পারফরম্যান্সের দিকগুলিতে উল্লেখযোগ্যভাবে পৃথক হয় না।
এম উইলিয়ামস

14
আপনার পদক্ষেপগুলি বেশ সঠিক বলে আমি মনে করি না। Thing myThing = Thing(...)অ্যাসাইনমেন্ট অপারেটরটি ব্যবহার করে না, এটি এখনও বলার মতোই অনুলিপি-নির্মিত হয়েছে Thing myThing(Thing(...)), এবং এটি কোনও ডিফল্ট-নির্মিত-তে জড়িত না Thing(সম্পাদনা করুন: পোস্টটি পরবর্তীকালে সংশোধন করা হয়েছিল)
অ্যাশলেসব্রিন

1
সুতরাং আপনি বলতে পারেন যে দ্বিতীয় লাইনটি ভুল, কারণ এটি কোনও আপাত কারণ ছাড়াই সংস্থানগুলি অপচয় করে। অবশ্যই এটি সম্ভব যে প্রথম উদাহরণটি তৈরি করা কিছু পার্শ্ব প্রতিক্রিয়াগুলির জন্য ইচ্ছাকৃত, তবে এটি আরও খারাপ (স্টাইলিস্টিকালি)।
এমকে

3
না, @ জ্যারেড, এটির নিশ্চয়তা নেই। কম্পাইলার সেই অপ্টিমাইজেশানটি সম্পাদন করতে বেছে নিলেও, অনুলিপি নির্মাণকারীকে এখনও অ্যাক্সেসযোগ্য হওয়া দরকার (যেমন, সুরক্ষিত বা ব্যক্তিগত নয়), এমনকি এটি প্রয়োগ করা হয়নি বা কল না করা হলেও।
রব কেনেডি

3
এটি প্রদর্শিত হয় অনুলিপিটিও অনুলিপি করা যেতে পারে যদিও অনুলিপি নির্মাণকারীর পার্শ্ব-প্রতিক্রিয়া রয়েছে - আমার উত্তর দেখুন: stackoverflow.com/questions/2722879/…
ডগলাস লিডার

31

আমি মনে করি আপনি দ্বিতীয় লাইনের সাথে বোঝাতে চাইছেন:

Thing *thing = new Thing("uiae");

যা হ'ল নতুন গতিশীল অবজেক্ট তৈরি করার (ডাইনামিক বাইন্ডিং এবং পলিমারফিজমের জন্য প্রয়োজনীয়) এবং তাদের ঠিকানাটি কোনও পয়েন্টারে সংরক্ষণ করার জন্য way আপনার কোড জারেডপার বর্ণিত হিসাবে কাজ করে, যেমন দুটি বস্তু তৈরি করে (একটি পাস করেছে const char*, অন্যটি পাস করেছে const Thing&), এবং তারপরে ~Thing()প্রথম অবজেক্টে ( const char*একটিকে) ডিস্ট্রাক্টরকে ( একটি ) কল করে ।

বিপরীতে, এটি:

Thing thing("uiae");

একটি স্ট্যাটিক অবজেক্ট তৈরি করে যা বর্তমান স্কোপটি থেকে বেরিয়ে আসার পরে স্বয়ংক্রিয়ভাবে ধ্বংস হয়ে যায়।


1
দুর্ভাগ্যক্রমে, এটি প্রকৃতপক্ষে অটো_পিটার, ইউনিক_পিটার বা সম্পর্কিত ব্যবহারের পরিবর্তে নতুন গতিশীল অবজেক্ট তৈরির সর্বাধিক সাধারণ উপায়।
ফ্রেড নুরক

3
ওপির প্রশ্নটি সঠিক ছিল, এই উত্তরটি পুরোপুরি অন্য একটি বিষয়কে উদ্বেগ করেছে (@ জ্যারেডপারের উত্তর দেখুন)
সিলম্যাথোরন

21

সংকলকটি দ্বিতীয় ফর্মটিকে প্রথম ফর্মটিতে ভালভাবে অনুকূলিত করতে পারে তবে এটি করার দরকার নেই।

#include <iostream>

class A
{
    public:
        A() { std::cerr << "Empty constructor" << std::endl; }
        A(const A&) { std::cerr << "Copy constructor" << std::endl; }
        A(const char* str) { std::cerr << "char constructor: " << str << std::endl; }
        ~A() { std::cerr << "destructor" << std::endl; }
};

void direct()
{
    std::cerr << std::endl << "TEST: " << __FUNCTION__ << std::endl;
    A a(__FUNCTION__);
    static_cast<void>(a); // avoid warnings about unused variables
}

void assignment()
{
    std::cerr << std::endl << "TEST: " << __FUNCTION__ << std::endl;
    A a = A(__FUNCTION__);
    static_cast<void>(a); // avoid warnings about unused variables
}

void prove_copy_constructor_is_called()
{
    std::cerr << std::endl << "TEST: " << __FUNCTION__ << std::endl;
    A a(__FUNCTION__);
    A b = a;
    static_cast<void>(b); // avoid warnings about unused variables
}

int main()
{
    direct();
    assignment();
    prove_copy_constructor_is_called();
    return 0;
}

জিসিসি ৪.৪ থেকে আউটপুট:

TEST: direct
char constructor: direct
destructor

TEST: assignment
char constructor: assignment
destructor

TEST: prove_copy_constructor_is_called
char constructor: prove_copy_constructor_is_called
Copy constructor
destructor
destructor

অকার্যকর কাটগুলির উদ্দেশ্য কী?
স্টিফেন ক্রস

1
@ স্টেফেন অব্যবহৃত ভেরিয়েবল সম্পর্কে সতর্কতা এড়ান।
ডগলাস লিডার

10

বেশ সহজভাবে, উভয় লাইন স্ট্যাকের উপর বস্তু তৈরি করে, বরং 'নতুন' এর মতো গাদা করার পরিবর্তে। দ্বিতীয় লাইনটি আসলে একটি অনুলিপি নির্মাণকারীকে দ্বিতীয় কল জড়িত, তাই এটি এড়ানো উচিত (মন্তব্যগুলিতে নির্দেশিত হিসাবে এটিও সংশোধন করা দরকার)। আপনার ছোট ছোট বস্তুর জন্য স্ট্যাকটি যথাসম্ভব দ্রুত ব্যবহার করা উচিত, তবে যদি আপনার বস্তুগুলি স্ট্যাক ফ্রেমের চেয়ে বেশি দিন বেঁচে থাকে তবে স্পষ্টতই এটি ভুল পছন্দ।


স্ট্যাক যেমন গাদা উপর উল্টোদিকে উপর শুরু করতে গিয়ে বস্তুর মধ্যে পার্থক্য (যে ব্যবহার করছে অপরিচিত তাদের জন্য নতুন এবং ব্যবহার করছেন না নতুন ), এখানে একটি ভাল থ্রেড আছে।
edmqkk

2

আদর্শভাবে, একটি সংকলক দ্বিতীয়টি অনুকূলিত করবে, তবে এটির প্রয়োজন নেই। প্রথমটি সেরা উপায়। যাইহোক, সি ++ এ স্ট্যাক এবং হিপগুলির মধ্যে পার্থক্য বুঝতে পেরে এটি বেশ সমালোচিত, আপনাকে অবশ্যই নিজের গাদা স্মৃতি পরিচালনা করতে হবে।


সংকলক গ্যারান্টি দিতে পারে যে অনুলিপি নির্মাণকারী এর পার্শ্ব প্রতিক্রিয়া নেই (যেমন I / O)?
স্টিফেন ক্রস

@ স্টেফেন - অনুলিপি নির্ধারক আমি / ও করেন কিনা তাতে কিছু যায় আসে না - আমার উত্তর দেখুন stackoverflow.com/questions/2722879/…
ডগলাস লিডার

ঠিক আছে, আমি দেখছি, সংকলকটিকে দ্বিতীয় ফর্মটিকে প্রথমটিতে রূপান্তরিত করার অনুমতি দেওয়া হয়েছে এবং এর মাধ্যমে অনুলিপিটি অনুলিপি করতে এড়ানো যায়।
স্টিফেন ক্রস

2

আমি এটির সাথে কিছুটা খেলেছি এবং যখন কোনও কনস্ট্রাক্টর কোনও যুক্তি না নেয় তখন সিনট্যাক্সটি বেশ অদ্ভুত বলে মনে হয়। আমাকে একটি উদাহরণ দিতে দাও:

#include <iostream> 

using namespace std;

class Thing
{
public:
    Thing();
};

Thing::Thing()
{
    cout << "Hi" << endl;
}

int main()
{
    //Thing myThing(); // Does not work
    Thing myThing; // Works

}

তাই কেবল থিং মাইথিং ডাব্লু / ও বন্ধনী লিখলে প্রকৃতপক্ষে কনস্ট্রাক্টরকে কল করা হয়, যখন থিং মাইথিং () সংকলকটিকে আপনি একটি ফাংশন পয়েন্টার বা কিছু তৈরি করতে চান তা বানায় ?? !!


6
এটি সি ++ তে একটি সুপরিচিত সিনট্যাকটিক দ্ব্যর্থতা। আপনি যখন "ইনট র্যান্ড ()" লিখেন, সংকলকটি আপনার "ইন্ট তৈরি করা এবং এটি ডিফল্ট-ইনিশিয়েলাইজ করা" বা "ফাংশন র‌্যান্ড ঘোষিত করা" বোঝায় কিনা তা জানতে পারে না। নিয়মটি হ'ল এটি যখনই সম্ভব সম্ভব পরে পছন্দ করে।
jpalecek


2

জারেডপার উত্তর সংযোজন

1-সাধারন কর্টর, অস্থায়ী বস্তুর সাথে 2 য় ফাংশন-এর মতো সিটার।

এই উত্সটি অন্য কোথাও এখানে সংকলন করুন http://melpon.org/wandbox/ বিভিন্ন সংকলক সহ

// turn off rvo for clang, gcc with '-fno-elide-constructors'

#include <stdio.h>
class Thing {
public:
    Thing(const char*){puts(__FUNCTION__ );}
    Thing(const Thing&){puts(__FUNCTION__ );}   
    ~Thing(){puts(__FUNCTION__);}
};
int main(int /*argc*/, const char** /*argv*/) {
    Thing myThing = Thing("asdf");
}

এবং আপনি ফলাফল দেখতে পাবেন।

আইএসও / আইইসি 14882 2003-10-15 থেকে

8.5, অংশ 12

আপনার 1 ম, দ্বিতীয় নির্মাণকে প্রত্যক্ষ-সূচনা বলা হয়

12.1, অংশ 13

একটি ফাংশনাল নোটেশন ধরণের রূপান্তর (5.2.3) এর ধরণের নতুন অবজেক্ট তৈরি করতে ব্যবহার করা যেতে পারে। [দ্রষ্টব্য: বাক্য গঠনটি নির্মাণকারীর একটি সুস্পষ্ট কলের মতো দেখায়। ] ... এই উপায়ে তৈরি করা কোনও বস্তু নামবিহীন। [দ্রষ্টব্য: 12.2 অস্থায়ী বস্তুর আজীবন বর্ণনা করে। ] [দ্রষ্টব্য: সুস্পষ্ট কনস্ট্রাক্টর কলগুলি লভ্য ফল দেয় না, দেখুন 3.10। ]


আরভিও সম্পর্কে কোথায় পড়বেন:

12 বিশেষ সদস্য ফাংশন / 12.8 বর্গ বিষয়বস্তু অনুলিপি / পার্ট 15

যখন নির্দিষ্ট মানদণ্ডগুলি পূরণ করা হয়, কোনও প্রয়োগকে ক্লাস অবজেক্টের অনুলিপি তৈরির কাজ বাদ দিতে দেওয়া হয়, এমনকি যদি অবজেক্টটির অনুলিপি নির্মাণকারী এবং / অথবা ডেস্ট্রাক্টরের পার্শ্ব প্রতিক্রিয়া থাকে

এ জাতীয় অনুলিপি-আচরণ দেখতে মন্তব্য থেকে সংকলক পতাকা দিয়ে এটি বন্ধ করুন)

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.