ডিফল্ট কনস্ট্রাক্টর এবং ডেস্ট্রাক্টরারের জন্য কীভাবে "=" ডিফল্ট "" {} "থেকে আলাদা?


169

আমি প্রাথমিকভাবে এটি কেবল ধ্বংসকারীদের সম্পর্কে একটি প্রশ্ন হিসাবে পোস্ট করেছি তবে এখন আমি ডিফল্ট নির্মাণকারীর বিবেচনা যুক্ত করছি। মূল প্রশ্নটি এখানে:

আমি যদি আমার ক্লাসটিকে এমন একটি ডেস্ট্রাক্টর দিতে চাই যা ভার্চুয়াল, তবে অন্যথায় সংকলকটি যা উত্পন্ন করে, আমি তার ব্যবহার করতে পারি =default:

class Widget {
public:
   virtual ~Widget() = default;
};

তবে মনে হয় একটি খালি সংজ্ঞা ব্যবহার করে আমি কম টাইপ করে একই প্রভাব পেতে পারি:

class Widget {
public:
   virtual ~Widget() {}
};

এই দুটি সংজ্ঞা আলাদাভাবে আচরণ করার কোনও উপায় আছে কি?

এই প্রশ্নের জন্য পোস্ট করা জবাবগুলির ভিত্তিতে, ডিফল্ট নির্মাণকারীর জন্য পরিস্থিতি একই রকম মনে হয়। ডিস্ট্রাক্টরদের জন্য " =default" এবং " {}" এর মধ্যে অর্থের প্রায় কোনও পার্থক্য নেই, ডিফল্ট কনস্ট্রাক্টরগুলির জন্য এই বিকল্পগুলির মধ্যে প্রায় একইভাবে অর্থের কোনও পার্থক্য নেই? এটি হ'ল আমি ধরে নিচ্ছি যে আমি একটি প্রকার তৈরি করতে চাই যেখানে সেই ধরণের অবজেক্টগুলি উভয়ই তৈরি এবং ধ্বংস হবে, আমি কেন বলতে চাই

Widget() = default;

পরিবর্তে

Widget() {}

?

এই প্রশ্নের মূল পোস্টিং কিছু এসও বিধি লঙ্ঘন করার পরে যদি এই প্রশ্নটি প্রসারিত করে তবে আমি ক্ষমা চাই। ডিফল্ট নির্মাতাদের জন্য প্রায় অভিন্ন প্রশ্ন পোস্ট করা আমাকে কম পছন্দসই বিকল্প হিসাবে আঘাত করেছে।


1
আমি জানি না, তবে = defaultএটি আরও স্পষ্টত ইমো এবং এটি নির্মাণকারীর সাথে সহায়তার সাথে সামঞ্জস্যপূর্ণ।
ক্রিস

11
আমি নিশ্চিতভাবে জানি না, তবে আমি মনে করি প্রাক্তনটি "তুচ্ছ ডেস্ট্রাক্টর" এর সংজ্ঞা অনুসারে মেনে চলেছেন, যদিও দ্বিতীয়টি তা করেন না। সুতরাং std::has_trivial_destructor<Widget>::valueহয় trueপ্রথম, কিন্তু falseসেকেন্ডের জন্য। এর কী কী প্রভাব পড়ছে তা আমিও জানি না। :)
GManNickG

10
ভার্চুয়াল ডেস্ট্রাক্টর কখনই তুচ্ছ হয় না।
ড্যান্টন

@ লুকড্যান্টন: আমি মনে করি চোখ খোলে এবং কোডটি দেখলে খুব কার্যকর হবে! সংশোধন করার জন্য ধন্যবাদ।
GManNickG

উত্তর:


103

ডেস্ট্রাক্টরের চেয়ে কনস্ট্রাক্টরদের সম্পর্কে জিজ্ঞাসা করার সময় এটি সম্পূর্ণ আলাদা প্রশ্ন।

যদি আপনার ডেস্ট্রাক্টর হয় virtualতবে পার্থক্যটি নগণ্য, যেমন হাওয়ার্ড নির্দেশ করেছেন । তবে, যদি আপনার ডেস্ট্রাক্টরটি অ-ভার্চুয়াল হয় , তবে এটি সম্পূর্ণ আলাদা গল্প। নির্মাতাদের ক্ষেত্রেও একই কথা।

= defaultবিশেষ সদস্য ফাংশনগুলির জন্য সিনট্যাক্স ব্যবহার করা (ডিফল্ট কনস্ট্রাক্টর, কপি / মুভ কনস্ট্রাক্টর / অ্যাসাইনমেন্ট, ডেস্ট্রাক্টর ইত্যাদি) অর্থ সহজভাবে করা থেকে খুব আলাদা কিছু {}। পরবর্তীগুলির সাথে, ফাংশনটি "ব্যবহারকারী দ্বারা সরবরাহিত" হয়ে যায়। এবং এটি সবকিছু পরিবর্তন করে।

এটি সি ++ 11 এর সংজ্ঞা অনুসারে একটি তুচ্ছ শ্রেণি:

struct Trivial
{
  int foo;
};

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

এই:

struct NotTrivial
{
  int foo;

  NotTrivial() {}
};

নামটি যেমন বোঝায়, এটি আর তুচ্ছ নয়। এটিতে একটি ডিফল্ট কনস্ট্রাক্টর রয়েছে যা ব্যবহারকারী দ্বারা সরবরাহিত। এটি খালি থাকলে কিছু যায় আসে না; সি ++ 11 এর নিয়মগুলির হিসাবে, এটি তুচ্ছ ধরনের হতে পারে না।

এই:

struct Trivial2
{
  int foo;

  Trivial2() = default;
};

নাম হিসাবে আবার বোঝা যাচ্ছে, এটি একটি তুচ্ছ ধরনের। কেন? কারণ আপনি সংকলকটিকে স্বয়ংক্রিয়ভাবে ডিফল্ট কনস্ট্রাক্টর তৈরি করতে বলেছিলেন। কনস্ট্রাক্টর তাই "ব্যবহারকারী দ্বারা সরবরাহিত" নয়। এবং তাই, প্রকারটি তুচ্ছ হিসাবে গণনা করা হয়, কারণ এটিতে কোনও ব্যবহারকারী-সরবরাহীকৃত ডিফল্ট কনস্ট্রাক্টর নেই।

= defaultসিনট্যাক্স কপি কনস্ট্রাকটর / নিয়োগ, যখন আপনি সদস্য ফাংশন যে এই ধরনের ফাংশন সৃষ্টি প্রতিরোধ যোগ মত জিনিসগুলি জন্য প্রধানত নেই। তবে এটি সংকলক থেকেও বিশেষ আচরণকে ট্রিগার করে, তাই এটি ডিফল্ট নির্মাণকারী / ধ্বংসকারীদের ক্ষেত্রেও কার্যকর।


2
সুতরাং মূল সমস্যাটি মনে হয় যে ফলাফল প্রাপ্ত শ্রেণিটি তুচ্ছ, এবং এই ইস্যুটির মূল অন্তর্ভুক্তটি হ'ল একটি বিশেষ ফাংশন যা ব্যবহারকারী দ্বারা ঘোষিত ( =defaultফাংশনগুলির ক্ষেত্রে এটি ) এবং ব্যবহারকারী দ্বারা সরবরাহিত (যা ক্ষেত্রে এটি {}) ফাংশনগুলির মধ্যে পার্থক্য । ব্যবহারকারী-ঘোষিত এবং ব্যবহারকারী-সরবরাহিত উভয় ফাংশনই অন্যান্য বিশেষ সদস্য ফাংশন (যেমন, কোনও ব্যবহারকারী-ঘোষিত ডেস্ট্রাক্টর মুভ অপারেশনগুলির প্রজন্মকে বাধা দেয়) প্রতিরোধ করতে পারে, তবে কেবলমাত্র একটি ব্যবহারকারী-সরবরাহিত বিশেষ ফাংশন একটি শ্রেণি অ-তুচ্ছ হিসাবে উপস্থাপন করে। রাইট?
জানুন সমস্ত ওয়ানবনেবে

@ কুনইটআলওয়ান্নাবে: হ্যাঁ, এটি সাধারণ ধারণা।
নিকল বোলাস

আমি এটিকে গ্রহণযোগ্য উত্তর হিসাবে বেছে নিচ্ছি, কেবল কারণ এটি উভয় কনস্ট্রাক্টর এবং (হাওয়ার্ডের জবাবের রেফারেন্স দ্বারা) ডেস্ট্রাক্টরকে কভার করে।
26 এ 12

"এখানে C ++ 11 এর বিধি সম্পর্কিত যতটা অনুপস্থিত শব্দ বলে মনে হচ্ছে, আপনি তুচ্ছ একটি ধরণের অধিকার" আমি এটি ঠিক করেছি তবে আমি কী 100% নিশ্চিত তা জানতে চাইনি sure
jcoder

2
= defaultঅন্যান্য নির্মাণকারীর উপস্থিতি সত্ত্বেও সংকলকটিকে ডিফল্ট কনস্ট্রাক্টর তৈরি করতে বাধ্য করার জন্য দরকারী বলে মনে হচ্ছে; অন্য কোনও ব্যবহারকারী-ঘোষিত কনস্ট্রাক্টর সরবরাহ করা থাকলে ডিফল্ট কনস্ট্রাক্টর স্পষ্টভাবে ঘোষণা করা হয় না।
bgfvdu3w

42

তারা উভয়ই তুচ্ছ

ঘাঁটি এবং সদস্যদের নোসেপ্ট স্পেসিফিকেশনের উপর নির্ভর করে উভয়ের উভয়েরই একই নোসেপ্ট স্পেসিফিকেশন রয়েছে।

আমি এখনও অবধি কেবলমাত্র তফাতটি সনাক্ত করতে পারছি তা হ'ল যদি Widgetকোনও অ্যাক্সেসযোগ্য বা মোছা ডেস্ট্রাক্টর সহ বেস বা সদস্য থাকে:

struct A
{
private:
    ~A();
};

class Widget {
    A a_;
public:
#if 1
   virtual ~Widget() = default;
#else
   virtual ~Widget() {}
#endif
};

তারপরে =defaultসমাধানটি সংকলন করবে তবে Widgetধ্বংসাত্মক ধরণের হবে না। অর্থাৎ আপনি যদি কোনওটিকে ধ্বংস করার চেষ্টা করেন তবে আপনি Widgetএকটি সংকলন-সময় ত্রুটি পাবেন। তবে আপনি যদি তা না করেন তবে আপনি একটি কার্যনির্বাহী প্রোগ্রাম পেয়েছেন।

ওহ, আপনি যদি ব্যবহারকারী সরবরাহকৃত ডেস্ট্রাক্টর সরবরাহ করেন তবে জিনিসগুলি আপনাকে ধ্বংস করে কিনা তা সংকলন করবে না Widget:

test.cpp:8:7: error: field of type 'A' has private destructor
    A a_;
      ^
test.cpp:4:5: note: declared private here
    ~A();
    ^
1 error generated.

9
আকর্ষণীয়: অন্য কথায়, =default;সংকলকটি এটি ব্যবহার না করে ডেস্ট্রাক্টর তৈরি করবে না এবং তাই ত্রুটি ট্রিগার করবে না। এটি আমার কাছে অদ্ভুত বলে মনে হয়, তবুও বাগটি না হলেও। আমি মানতে পারি না যে এই আচরণটি স্ট্যান্ডার্ডে বাধ্যতামূলক
নিক বুগালিস

"তারপরে = ডিফল্ট সমাধানটি সংকলন করবে" না এটি হবে না।
ন্যানো

ত্রুটি বার্তাটি কী ছিল, এবং ভিএসের কোন সংস্করণ ছিল?
হাওয়ার্ড হিনান্ট

35

এর মধ্যে গুরুত্বপূর্ণ পার্থক্য

class B {
    public:
    B(){}
    int i;
    int j;
};

এবং

class B {
    public:
    B() = default;
    int i;
    int j;
};

এটি কি ডিফল্ট কনস্ট্রাক্টর হিসাবে সংজ্ঞায়িত -ব্যবহারকারী হিসাবে সংজ্ঞায়িতB() = default; হিসাবে বিবেচিত হয় ? এর অর্থ হ'ল হিসাবে মান-আরম্ভের ক্ষেত্রে

B* pb = new B();  // use of () triggers value-initialization

বিশেষ ধরণের সূচনা যা কোনও কনস্ট্রাক্টর ব্যবহার করে না তা সংঘটিত হবে এবং অন্তর্নির্মিত ধরণের জন্য এটি শূন্য-ইনিশিয়ালাইজেশন ঘটবে । এই ক্ষেত্রে B(){}জায়গা গ্রহণ করা হবে না। সি ++ স্ট্যান্ডার্ড n3337 § 8.5 / 7 বলছে

টি টাইপের কোনও অবজেক্টের মূল্য-সূচনা করার জন্য:

- যদি টি ব্যবহারকারীর দ্বারা সরবরাহিত কনস্ট্রাক্টর (12.1) সহ একটি (সম্ভবত সিভি-কোয়ালিটিভড) শ্রেণীর ধরণ (ক্লজ 9) হয় তবে টি এর জন্য ডিফল্ট কনস্ট্রাক্টর বলা হয় (এবং টি যদি অ্যাক্সেসযোগ্য ডিফল্ট কনস্ট্রাক্টর না থাকে তবে ইনিশিয়েশনটি খারাপ থাকে) );

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

- যদি টি একটি অ্যারের ধরণ হয় তবে প্রতিটি উপাদান মান-আরম্ভ হয়; - অন্যথায়, অবজেক্টটি শূন্য-সূচনাযুক্ত ized

উদাহরণ স্বরূপ:

#include <iostream>

class A {
    public:
    A(){}
    int i;
    int j;
};

class B {
    public:
    B() = default;
    int i;
    int j;
};

int main()
{
    for( int i = 0; i < 100; ++i) {
        A* pa = new A();
        B* pb = new B();
        std::cout << pa->i << "," << pa->j << std::endl;
        std::cout << pb->i << "," << pb->j << std::endl;
        delete pa;
        delete pb;
    }
  return 0;
}

সম্ভাব্য ফলাফল:

0,0
0,0
145084416,0
0,0
145084432,0
0,0
145084416,0
//...

http://ideone.com/k8mBrd


তারপরে, "{}" এবং "= ডিফল্ট" কেন সর্বদা একটি স্টাডি :: স্ট্রিং আইডিয়োন . com/LMv5Uf শুরু করে ?
নওফেল বিজিএইচ

1
@ নওফেলবাগ ডিফল্ট কনস্ট্রাক্টর এ () {st স্ট্যান্ড :: স্ট্রিংয়ের জন্য ডিফল্ট কনস্ট্রাক্টরকে কল করে কারণ এটি নন-পিওডি টাইপ। স্ট্যান্ড :: স্ট্রিংয়ের ডিফল্ট কর্টর এটি শূন্য, 0 আকারের স্ট্রিংয়ে আরম্ভ করে । স্কেলারগুলির জন্য ডিফল্ট কর্টর কিছুই করে না: স্বয়ংক্রিয় স্টোরেজ সময়কাল (এবং তাদের সাবোবজেক্টস) সহ অবজেক্টগুলি অনির্দিষ্ট মানগুলির জন্য আরম্ভ করা হয়।
4pie0
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.