টেম্পোরারিগুলি কীভাবে বাতিল করবেন


107

ক্লাস ফু এর জন্য, নাম না দিয়ে কি এটির নির্মাণ নিষিদ্ধ করার কোনও উপায় আছে?

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

Foo("hi");

এবং কেবলমাত্র যদি আপনি এটির নাম রাখেন তবে নীচের মতো?

Foo my_foo("hi");

প্রথমটির জীবদ্দশায় কেবল বিবৃতি দেওয়া হয়, এবং দ্বিতীয়টি হ'ল সংযুক্তি ব্লক। আমার ব্যবহারের ক্ষেত্রে, Fooকনস্ট্রাক্টর এবং ডেস্ট্রাক্টরের মধ্যে সময়টি পরিমাপ করছে। যেহেতু আমি কখনই স্থানীয় পরিবর্তনশীলকে উল্লেখ করি না, তাই আমি প্রায়শই এটি যুক্ত করতে ভুলে যাই এবং দুর্ঘটনাক্রমে আজীবন পরিবর্তন করি the পরিবর্তে আমি একটি সংকলন সময় ত্রুটি পেতে চাই।


8
এটি মিটেক্স লক প্রহরীদের পক্ষেও কার্যকর হতে পারে।
lucas clemente

1
ভাল, আপনি নিজের সি ++ সংকলক যেখানে এটি নিষিদ্ধ ছিল লিখতে পারেন , তবে কঠোরভাবে বলতে গেলে এটি তখন সি ++ হবে না। এছাড়াও এমন জায়গাগুলি রয়েছে যেখানে অস্থায়ী কাজগুলি কার্যকর হবে যেমন কোনও ফাংশন থেকে কোনও জিনিস ফেরত দেওয়ার জন্য উদাহরণস্বরূপ (যেমন return std::string("Foo");)
কিছু প্রোগ্রামার ডিউড

2
নাহ, আপনি এটি করতে পারবেন না, দুঃখিত
আর্মেন ​​সিরুনিয়ান

2
আপনার ধর্মের উপর নির্ভর করে এটি এমন একটি ঘটনা হতে পারে যেখানে ম্যাক্রোগুলি কার্যকর হতে পারে (কেবলমাত্র সেই ম্যাক্রোর মাধ্যমে সেই টাইপটি ইউএসইগ দ্বারা সর্বদা পরিবর্তনযোগ্য তৈরি করে)
প্লাজমাএইচএইচ

3
একটি সংকলক হ্যাক দ্বারা সিন্টেক্সিকভাবে প্রতিরোধ করতে চাই এমন কিছুের চেয়ে আমি আমার লিন্ট সরঞ্জামটি ধরতে চাই এমন কিছুর মতো মনে হয়।
ওয়ারেন পি

উত্তর:


101

আর একটি ম্যাক্রো-ভিত্তিক সমাধান:

#define Foo class Foo

বিবৃতিটি Foo("hi");প্রসারিত হয় class Foo("hi");, যা দূষিত; তবে Foo a("hi")প্রসারিত হয় class Foo a("hi")যা সঠিক।

এটির সুবিধাটি রয়েছে যে এটি বিদ্যমান (সঠিক) কোডের সাথে উভয় উত্স- এবং বাইনারি-সামঞ্জস্যপূর্ণ। (এই দাবিটি পুরোপুরি সঠিক নয় - দয়া করে জোহানেস শ্যাউবের মন্তব্য এবং নীচের আলোচনার আলোচনাটি দেখুন: "আপনি কীভাবে জানতে পারবেন যে এটি বিদ্যমান কোডের সাথে উত্সযুক্ত? তার বন্ধুতে তার শিরোনামটি অন্তর্ভুক্ত করা হয়েছে এবং f) (F int foo = 0;} যা পূর্বে জরিমানা সংকলিত হয়েছে এবং এখন ভুল সংকলন করে! এছাড়াও, ক্লাস ফু এর সদস্য ফাংশন সংজ্ঞায়িত প্রতিটি লাইন ব্যর্থ হয়: শূন্য শ্রেণি ফু: বার () (} " )


51
আপনি কীভাবে জানতে পারবেন যে এটি বিদ্যমান কোডের সাথে উত্স সঙ্গতিপূর্ণ? তার void f() { int Foo = 0; }বন্ধুটিতে তার শিরোলেখ অন্তর্ভুক্ত রয়েছে এবং এটি আগে জরিমানা এবং এখন ভুল সংকলন করেছে ! এছাড়াও, যে লাইন বর্গ ফু সদস্য ফাংশন সংজ্ঞায়িত যে ব্যর্থ হলে: void class Foo::bar() {}
জোহানেস স্কাউব -

21
এটি কীভাবে এত বেশি ভোট পাবে? কেবলমাত্র @ জোহানেস শ্যাব-লিটব মন্তব্যটি দেখুন এবং আপনি বুঝতে পারবেন এটি সত্যিই খারাপ সমাধান। কারণ সদস্য ফাংশনগুলির সমস্ত সংজ্ঞা এর পরে অবৈধ .. আমার দিক থেকে -1
আমির

2
@ জাস্টম্যাক্সিমিউম পাওয়ার: আমি আশা করি এটি ব্যঙ্গাত্মক ছিল কারণ যদি তা না হয় তবে এটি আবার খারাপ (আরও খারাপ পড়ুন) কাজ করে। কারণ আমরা এটি অপরিবর্তিত করার পরে স্কোয়ার একে ফিরে এসেছি যার অর্থ আপনি Foo("Hi")এখনই Foo.cpp- এর ভিতরে একই লাইনে একটি সংকলন ত্রুটি (যা ওপি অনুগ্রহ করে) পাবেন না
আমির

1
আমির না আমি সিরিয়াস মার্টিন সি মার্টিন Foo এর ব্যবহার রক্ষার জন্য এটি ব্যবহারের পরিকল্পনা করছেন বাস্তবায়ন নয়।
জাস্টম্যাক্সিমিয়ামম পাওয়ার

1
আমি ভিজ্যুয়াল স্টুডিও 2012 এ চেষ্টা করেছি এবং class Foo("hi");সংকলনের জন্য ঠিক আছে।
ফ্রেসকি

71

একটু হ্যাক কেমন হয়

class Foo
{
    public:
        Foo (const char*) {}
};

void Foo (float);


int main ()
{
    Foo ("hello"); // error
    class Foo a("hi"); // OK
    return 1;
}

1
দুর্দান্ত হ্যাক! একটি নোট: Foo a("hi");(ছাড়া class) একটি ত্রুটি হতে পারে।
বিটমাস্ক

আমি নিশ্চিত নই যে আমি বুঝেছি. ফু ("হ্যালো") অকার্যকর Foo (ভাসা) কল করার চেষ্টা করে এবং এর ফলে কোনও লিঙ্কার ত্রুটি হয়? তবে ফু কর্টারের পরিবর্তে কেন ফ্লোট সংস্করণ বলা হয়?
undu

2
আনডু, এইচএম আপনি কোন সংকলকটি ব্যবহার করছেন? জিসিসি 3.4 অভিযোগ করে যে ভাসতে কোনও রূপান্তর নেই। এটি কোনও ফাংশনকে কল করার চেষ্টা করে Fooকারণ এটি একটি শ্রেণীর চেয়ে বেশি অগ্রাধিকার নেয়।

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

1
@ ডিডিয়ারক নং, Foo::Foo("hi")সি ++ এ অনুমোদিত নয়।
জোহানেস স্কাউব -

44

কনস্ট্রাক্টরকে বেসরকারী করুন তবে ক্লাসটিকে একটি তৈরি পদ্ধতি দিন।


9
-1: এটি কীভাবে একেবারেই ওপির সমস্যাটি সমাধান করে? আপনি এখনও লিখতে পারেন Foo::create();উপরFoo const & x = Foo::create();
টমাস Eding

@ থমাসএডিংয়ের পরে আমি অনুমান করি আপনি ঠিক বলেছেন, এটি ওপির মূল সমস্যাটি সমাধান করে না, তবে কেবল তাকে ভাবতে বাধ্য করে এবং সে যে ভুলটি করছে তার ভুল না করে।
dchhetri

1
@ থমাসে আপনি ক্ষুব্ধ ব্যবহারকারীদের থেকে নিজেকে রক্ষা করতে পারবেন না যারা এই সিস্টেমটি ভাঙতে চান। এমনকি @ একাটমুরের হ্যাক দিয়েও আপনি বলতে পারেন std::common_type<Foo>::type()এবং আপনি একটি অস্থায়ী হয়ে যান। বা এমনকি typedef Foo bar; bar()
জোহানেস স্কাউব - 21

@ জোহানেস শ্যাব-লিটব: তবে বড় পার্থক্যটি ভুলক্রমে হয়েছিল কিনা তা নয়। std::common_type<Foo>::type()ভুল করে টাইপ করার প্রায় কোনও উপায় নেই । Foo const & x = ...দুর্ঘটনার কারণে এড়িয়ে যাওয়া পুরোপুরি বিশ্বাসযোগ্য।
টমাস এডিং

24

এটির ফলে একটি সংকলক ত্রুটি হয় না, তবে একটি রানটাইম ত্রুটি। একটি ভুল সময় পরিমাপ করার পরিবর্তে, আপনি একটি ব্যতিক্রম পান যা গ্রহণযোগ্যও হতে পারে।

আপনি যে কোনও কনস্ট্রাক্টরকে রক্ষা করতে চান তার একটি ডিফল্ট যুক্তি প্রয়োজন যার set(guard)উপরে ডাকা হয়।

struct Guard {
  Guard()
    :guardflagp()
  { }

  ~Guard() {
    assert(guardflagp && "Forgot to call guard?");
    *guardflagp = 0;
  }

  void *set(Guard const *&guardflag) {
    if(guardflagp) {
      *guardflagp = 0;
    }

    guardflagp = &guardflag;
    *guardflagp = this;
  }

private:
  Guard const **guardflagp;
};

class Foo {
public:
  Foo(const char *arg1, Guard &&g = Guard()) 
    :guard()
  { g.set(guard); }

  ~Foo() {
    assert(!guard && "A Foo object cannot be temporary!");
  }

private:
  mutable Guard const *guard;
}; 

বৈশিষ্ট্যগুলি হ'ল:

Foo f() {
  // OK (no temporary)
  Foo f1("hello");

  // may throw (may introduce a temporary on behalf of the compiler)
  Foo f2 = "hello";

  // may throw (introduces a temporary that may be optimized away
  Foo f3 = Foo("hello");

  // OK (no temporary)
  Foo f4{"hello"};

  // OK (no temporary)
  Foo f = { "hello" };

  // always throws
  Foo("hello");

  // OK (normal copy)
  return f;

  // may throw (may introduce a temporary on behalf of the compiler)
  return "hello";

  // OK (initialized temporary lives longer than its initializers)
  return { "hello" };
}

int main() {
  // OK (it's f that created the temporary in its body)
  f();

  // OK (normal copy)
  Foo g1(f());

  // OK (normal copy)
  Foo g2 = f();
}

কেস এর ক্ষেত্রে f2, f3এবং এর প্রত্যাবর্তন "hello"চাওয়া হতে পারে না। নিক্ষেপ রোধ করতে, আপনি অনুলিপিটির guardউত্সের পরিবর্তে এখন আমাদের রক্ষা করতে পুনরায় সেট করে একটি অনুলিপিটির উত্সকে একটি অস্থায়ী হওয়ার অনুমতি দিতে পারেন । এখন আপনি আরও দেখুন যে আমরা উপরের পয়েন্টারগুলি কেন ব্যবহার করেছি - এটি আমাদের নমনীয় হতে দেয়।

class Foo {
public:
  Foo(const char *arg1, Guard &&g = Guard()) 
    :guard()
  { g.set(guard); }

  Foo(Foo &&other)
    :guard(other.guard)
  {
    if(guard) {
      guard->set(guard);
    }
  }

  Foo(const Foo& other)
    :guard(other.guard)
  {
    if(guard) {
      guard->set(guard);
    }
  }

  ~Foo() {
    assert(!guard && "A Foo object cannot be temporary!");
  }

private:
  mutable Guard const *guard;
}; 

জন্য বৈশিষ্ট্য f2, f3এবং জন্য return "hello"এখন সবসময় // OK


2
Foo f = "hello"; // may throwএই কোডটি কখনও ব্যবহার না করে আমাকে ভয় দেখানোর জন্য এটি যথেষ্ট।
থমাস এডিং

4
@ থমাস, আমি কন্সট্রাক্টরকে চিহ্নিত করার পরামর্শ দিই explicitএবং তারপরে এ জাতীয় কোডটি আর সংকলন করা হবে না। লক্ষ্যটি ছিল অস্থায়ীভাবে fotbid করা, এবং এটি করে। যদি আপনি ভীত হন, আপনি অনুলিপি হতে অনুলিপি হতে অনুলিপি হতে অনুলিপি করতে অনুলিপি করতে অনুলিপি করতে একটি অনুলিপি উত্স সেট করে বা এড়াতে পারবেন না। যদি এখনও এটি অস্থায়ী হিসাবে শেষ হয় তবে কেবলমাত্র কয়েকটি অনুলিপিগুলির চূড়ান্ত বস্তু নিক্ষেপ করতে পারে।
জোহানেস স্কাউব -

2
আমার দেবতা। আমি সি ++ এবং সি ++ 11-এ নবজাতক নই, তবে কীভাবে এটি কাজ করে আমি বুঝতে পারি না। আপনি দয়া করে কয়েকটি ব্যাখ্যা যোগ করতে পারেন? ..
মিখাইল

6
@ মিখাইল একই পয়েন্টগুলিতে ধ্বংস হওয়া অস্থায়ী বস্তুগুলির ধ্বংসের ক্রম হ'ল তাদের নির্মাণের বিপরীত ক্রম। কলার যে ডিফল্ট তর্কটি অতিক্রম করে তা অস্থায়ী। যদি বস্তুটিও Fooএকটি অস্থায়ী হয় এবং এর আজীবন একইরূপে ডিফল্ট আর্গুমেন্টের সমাপ্ত হয়, তবে Fooঅবজেক্টের ডটরটি ডিফল্ট আর্গুমেন্টের ডটারের আগে ডাকা হবে, কারণ পূর্ববর্তীটির পরে তৈরি হয়েছিল।
জোহানেস স্কাউব -

1
@ জোহানেস শ্যাব-লিটব খুব সুন্দর কৌশল। আমি সত্যিই ভেবেছিলাম এটা পার্থক্য করা অসম্ভব Foo(...);এবং Foo foo(...);ভিতর থেকে Foo
মিখাইল

18

কয়েক বছর আগে আমি জিএনইউ সি ++ কম্পাইলারের জন্য একটি প্যাচ লিখেছিলাম যা সেই পরিস্থিতির জন্য একটি নতুন সতর্কতা বিকল্প যুক্ত করে। এটি একটি বাগজিলা আইটেমে ট্র্যাক করা হয়েছে ।

দুর্ভাগ্যক্রমে, জিসিসি বাগজিলা একটি সমাধিস্থল, যেখানে প্যাচ-অন্তর্ভুক্ত বৈশিষ্ট্য প্রস্তাবনাগুলি মারা যেতে পারে। :)

কোডটিতে এই প্রশ্নের মূল বিষয়বস্তু ঠিক কী ধরণের বাগগুলি ধরার আকাঙ্ক্ষার দ্বারা প্রেরণা পেয়েছিল যা স্থানীয় বস্তুগুলিকে লকিং এবং আনলকিংয়ের জন্য গ্যাজেট হিসাবে ব্যবহার করে, মৃত্যুদন্ড কার্যকর করার সময় এবং এইজন্য পরিমাপ করে।


9

যেমনটি, আপনার প্রয়োগের সাথে, আপনি এটি করতে পারবেন না, তবে আপনি এই সুবিধাটি আপনার সুবিধার্থে ব্যবহার করতে পারেন:

অস্থায়ী বস্তুগুলি নিরপেক্ষ উল্লেখগুলির সাথে আবদ্ধ হতে পারে না

আপনি কোডটি ক্লাস থেকে একটি ফ্রিস্ট্যান্ডিং ফাংশনে নিয়ে যেতে পারেন যা একটি অ-কনস্ট্যান্ট রেফারেন্স প্যারামিটার নেয়। যদি আপনি এটি করেন, আপনি যদি একটি অস্থায়ী অ-নিরপেক্ষ রেফারেন্সকে আবদ্ধ করার চেষ্টা করে তবে আপনি একটি সংকলক ত্রুটি পাবেন।

কোড নমুনা

class Foo
{
    public:
        Foo(const char* ){}
        friend void InitMethod(Foo& obj);
};

void InitMethod(Foo& obj){}

int main()
{
    Foo myVar("InitMe");
    InitMethod(myVar);    //Works

    InitMethod("InitMe"); //Does not work  
    return 0;
}

আউটপুট

prog.cpp: In function int main()’:
prog.cpp:13: error: invalid initialization of non-const reference of type Foo&’ from a temporary of type const char*’
prog.cpp:7: error: in passing argument 1 of void InitMethod(Foo&)’

1
@ ডিডিয়ারসি: শর্তযুক্ত তারা একটি অতিরিক্ত ক্রিয়াকলাপ সরবরাহ করে so এটি না করা আপনার কাজ। আমরা মানদণ্ডের দ্বারা স্পষ্টভাবে অনুমোদিত নয় এমন কিছু অর্জনের জন্য উপায় অবলম্বন করার চেষ্টা করছি, সুতরাং অবশ্যই নিষেধাজ্ঞাগুলি থাকবে।
অলোক

@ ডিডিয়ার প্যারামিটার xএকটি নামযুক্ত বস্তু তাই এটি সত্য যে আমরা এটি নিষিদ্ধ করতে চাই তা স্পষ্ট নয়। আপনি যে কনস্ট্রাক্টরটি ব্যবহার করেছেন তা যদি স্পষ্ট হয় তবে লোকেরা সহজাতভাবে তা করতে পারে Foo f = Foo("hello");। আমি মনে করি এটি ব্যর্থ হলে তারা রেগে যাবে। আমার সমাধানটি প্রাথমিকভাবে এটিকে (এবং খুব অনুরূপ ক্ষেত্রে) একটি ব্যতিক্রম / দৃ an়-ব্যর্থতার সাথে প্রত্যাখ্যান করেছে এবং কেউ অভিযোগ করেছে।
জোহানেস স্কাউব -

@ জোহানেস শ্যাব-লিটব হ্যাঁ, ওপি বাইন্ডিং জোর করে কোনও নির্মাণকারীর দ্বারা উত্পাদিত মান বর্জন করতে চায়। আমার উদাহরণটি ভুল।
didierc

7

কেবলমাত্র একটি ডিফল্ট কনস্ট্রাক্টর নেই এবং প্রতিটি কনস্ট্রাক্টরের একটি দৃষ্টান্তের জন্য একটি রেফারেন্স প্রয়োজন।

#include <iostream>
using namespace std;

enum SelfRef { selfRef };

struct S
{
    S( SelfRef, S const & ) {}
};

int main()
{
    S a( selfRef, a );
}

3
চমৎকার ধারণা, কিন্তু আপনি এক পরিবর্তনশীল আছে তাড়াতাড়ি হিসাবে: S(selfRef, a);। : /
শিও

3
@ শিও S(SelfRef, S const& s) { assert(&s == this); }, যদি রানটাইম ত্রুটি গ্রহণযোগ্য হয়।

6

না, আমি আশঙ্কা করছি এটি সম্ভব নয়। তবে আপনি ম্যাক্রো তৈরি করে একই প্রভাব পেতে পারেন।

#define FOO(x) Foo _foo(x)

এটি স্থানে রেখে আপনি কেবল ফু মাই_ফু (এক্স) এর পরিবর্তে কেবল এফইও (এক্স) লিখতে পারেন।


5
আমি উঁচুতে যাচ্ছিলাম, কিন্তু তখন আমি দেখেছি "আপনি একটি ম্যাক্রো তৈরি করতে পারেন"।
গ্রিউজ

1
ঠিক আছে, আন্ডারস্কোরগুলি স্থির করুন। @ গ্রিভস - মৌলবাদী হবেন না। "এটি করা যায় না" এর চেয়ে "ম্যাক্রো ব্যবহার করুন" বলা ভাল।
amaurea

5
ঠিক আছে, এটা করা যায় না। আপনি সমস্যাটি একেবারেই সমাধান করেননি, এটি করা এখনও পুরোপুরি আইনী Foo();
কুকুরছানা

11
এখন আপনি এখানে অনড় হয়ে যাচ্ছেন। ফু ক্লাসটিকে কিছু জটিল করে নামকরণ করুন এবং ম্যাক্রো ফুটিকে কল করুন। সমস্যা সমাধান.
amaurea

8
এর মতো কিছু:class Do_not_use_this_class_directly_Only_use_it_via_the_FOO_macro;
বেঞ্জামিন লিন্ডলি

4

যেহেতু প্রাথমিক লক্ষ্যটি বাগগুলি প্রতিরোধ করা, তাই এটি বিবেচনা করুন:

struct Foo
{
  Foo( const char* ) { /* ... */ }
};

enum { Foo };

int main()
{
  struct Foo foo( "hi" ); // OK
  struct Foo( "hi" ); // fail
  Foo foo( "hi" ); // fail
  Foo( "hi" ); // fail
}

এইভাবে আপনি ভেরিয়েবলটির নাম রাখতে ভুলে যেতে পারবেন না এবং লিখতেও ভুলতে পারবেন না struct। ভার্বোজ, তবে নিরাপদ।


1

ওয়ান-প্যারামেট্রিক কনস্ট্রাক্টরকে স্পষ্ট হিসাবে ঘোষণা করুন এবং কেউ কখনও অজ্ঞাতসারে এই শ্রেণীর কোনও অবজেক্ট তৈরি করতে পারবেন না।

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

class Foo
{
public: 
  explicit Foo(const char*);
};

void fun(const Foo&);

কেবল এইভাবে ব্যবহার করা যেতে পারে

void g() {
  Foo a("text");
  fun(a);
}

তবে কখনও এইভাবে নয় (স্ট্যাকের উপর অস্থায়ী মাধ্যমে)

void g() {
  fun("text");
}

আরও দেখুন: আলেকজান্দ্রেস্কু, সি ++ কোডিং মান, আইটেম 40।


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